Move Class -- 移动类

Move Class

Refactoring contributed by Gerard M. Davison

You have a class that is in a package that contains other classes that it is not related to in function.

在包里有一个类和其他的类在功能上没啥关系。

Move the class to a more relevant package. Or create a new package if required for future use.

将这个类移动到相关的包里,或者创建一个将来可能会使用的包,并移动到里面。

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

Motivation

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 relevant parts.

如果类在其自身的包中有很多依赖关系,然后使用首先提取类分离相关的部分。

Another example where is this used often is to move String resource objects into sub a res package to simplify localization compilation.

将国际化的String resource objects移动到一个子包里,便于管理以及修改。


Mechanics

  • Move the class to its new folder on the source tree.
  • 将这个类移动到新的包中。
  • Remove any class files generated from compiling this class at its old location.
  • 移除所有使用此类源文件头的import语句。
  • Alter the package statement in the source file to reflect the new package.
  • 修改类的旧package语句为新的package语句。
  • Create import statements for any dependant classes in original package.
  • 为所有依赖此类的java文件中添加新的import语句。
  • Compile and test the class in its new package, updating and moving unit tests as required using this same method.
  • 编译,并将移动类的单元测试移动相应的包中。
  • Alter, and create in some cases, the import statements on any dependee class. Note this is easier if wide imports are not used.
  • Check for classes that might dynamically instantiate this class using java.lang.reflect or the ResourceBundle api. Also look for code that might reference this class as an absolute class literal.
  • 还需要修改通过反射生成移动类的代码,或者ResourceBundle相关东西。
  • Compile and test all code that was dependant on the original class.
  • 编译,更新一下单元测试中对移动类的依赖点。
  • Consider applying extractPackage when you have many classes of different functionality in a given package.
  • 当一个包中有不同功能时,考虑使用extractPackage重构手段。

Example

Lets look at the header of StringUtil

看下类StringUtil文件类头。

package org.davison.ui

// imports

public class StringUtil

...

We move the file and change the package header.

移除旧package添加新package。

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.

当所有的静态引用和动态引用解决后,测试一下。重构就算完成了。


通常在Ecplise中,选中要移动的类,拖动到待移动的包中,Ecplise会查找所有的引用点,并进行修改。但是一定还要根据作者的重构步骤,检查下待移动类的动态代码,将其修改掉,还有单元测试相关连的也需要修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值