Refactoring contributed by Gerard M. Davison
class org.davison.ui.TextThing class org.davison.ui.TextProcessor class org.davison.log.Logger depends on class org.davison.ui.StringUtil
class org.davison.ui.TextThing class org.davison.ui.TextProcessor class org.davison.log.Logger depends on class org.davison.util.StringUtil
Classes are often created in a packages close to where they are being used, this can make sense until the class starts to be re-used by other parts of the product. The package in question might also have just become too big. (I have a preference that my packages never have more than about 10 classes)
It is often better to move to this class to a package more related to it in form or function. This can help remove complex package level dependencies and make it easier for developers to find and re-use classes.
If there are many dependencies for the class within its own package, then Extract Class could be used first to split out the relavent parts.
Another example where is this used often is to move String resource objects into sub a res package to simplify localisation compilation.
Lets look at the header of StringUtil
package org.davison.ui // imports public class StringUtil ...
We move the file and change the package header.
package org.davison.util // imports public class StringUtil ...
I can now compile and unit test this class in its new package. If the unit tests are in a different package class file then they might need to be updated.
I can now go on to update the dependant classes. For example here I update the import statements, I have not used a wide imports in this example but the principle is the same.
package org.davison.log // imports import org.davison.ui.StringUtils; // more imports public class Logger ...
This becomes:
package org.davison.log // imports import org.davison.util.StringUtils; // more imports public class Logger ...
Again compile and test this new class with the imports.
As mentioned before there are other ways of dynamically loading classes. You may have to look for class literals and strings constants containing the fully qualified name of the old class.
// A class literal public Class m_utils = org.davison.ui.StringUtils.class; // A dynamically loaded class public Class m_utils = Class.forName("org.davison.ui.StringUtils"); // A loaded resource bundle public ResourceBundle m_bundle = ResourceBundle.getBundle( "org.davison.ui.StringUtils");
These can be fixed using simple find and replaces, these dynamic examples will also be found using the units tests for all classes.
// A class literal, this will be found by the compiler. public Class m_utils = org.davison.util.StringUtils.class; // A dynamically loaded class public Class m_utils = Class.forName("org.davison.util.StringUtils"); // A loaded resource bundle public ResourceBundle m_bundle = ResourceBundle.getBundle( "org.davison.util.StringUtils");
One all static and dynamic cases have been dealt with, and all unit tests have run. The refactoring is complete.
Consider using a tool to do this. See Chris Sequin's refactory or Woodenchair
--Martin Fowler