Move Method (搬移函数)

Summary: 

程序中,有个函数与其所驻类以外的另个一个函数进行更多的交流:调用后者,或者被后者调用。 java

 在该函数最常引用的类中创建一个有着相似行为的新函数。将旧函数变成一个单纯的委托函数,或是将旧函数彻底移除。 函数

Motivation:

“搬移函数”是重构理论的支柱。若是有一个类有太多行为,或若是一个类与另外一个类有太多合做而造成高度耦合,就能够办以函数。经过这种手段,可使系统中的类更简单,这些类最终也将更干净利落地实现系统交付的任务。 测试

Mechanics:

1. 检查源类中被源函数所使用的一切特性(包括字段和函数),考虑它们是否也该被搬移。 spa

若是某个特性只被打算搬移的那个函数用到,就应该将它一并搬移。若是另有其余函数使用了这个特性,能够考虑将使用该特性的全部函数全都一并搬移。有时候,搬移一组函数比逐一搬移简单些。 code

2.检查源类的子类和超类,看看是否有该函数的其余声明。 对象

若是出现其余声明,或许没法进行搬移,除非目标类也一样表现出多态性。 rem

3.在目标类中声明这个函数。 io

能够为此函数选择一个新名称—对目标类更有意义的名称 编译

    4. 将源函数的代码复制到目标函数中。调整后者,使其能在新类中正常运行 class

若是目标函数使用了源类中的特性,咱们得决定如何从目标函数引用源对象。若是目标类中没有相应的引用机制,就得把源对象的引用当作参数,传给新创建的目标函数。

若是源函数包含异常处理,咱们得判断逻辑上应该由哪一个类来处理这一异常。若是应该由源类来负责,就把异常处理留在原地。

5. 编译目标类

6. 决定如何从源函数正确引用目标对象。

  可能会有一个现成的字段或函数帮助取得目标对象。若是没有,就看可否轻松创建一个这样的函数。若是仍是不行,就得在源类中新建一个字段来保存目标对象。这多是一个永久性修改,但也可让它是暂时的,由于后继的其余重构项目可能会把这个新建字段去掉。

7.修改源函数,使之成为一个纯委托函数

8.编译,测试

9. 决定是否删除源函数,或将它看成一个委托函数保留下来

      若是要常常在源对象中引用目标函数,那么将源函数做为委托函数保留下来会比较简单。

10.若是要移除源函数,请将源类中对源函数的全部调用,替换为对目标函数的调用

11. 编译,测试。

范例

咱们用一个表示帐户的Account类来讲明这项重构

public class Account
{
    private AccountType type;

    private int daysOverdrawn;

    double overdraftCharge()
    {
        if( type.isPremium() )
        {
            double result = 10;
            if( daysOverdrawn > 7 )
            {
                result += ( daysOverdrawn - 7 ) * 0.85;
                return result;
            }
        }
        else
        {
            return daysOverdrawn * 1.75;
        }
        return 0;
    }

    double bankCharge(){
        double result = 4.5;
        if( daysOverdrawn > 0 )
        {
            result += overdraftCharge();
        }
        return result;
    }
}
假设有几种新帐户,每一种都有本身的“透支金额计费规则”。因此咱们但愿将overdraftCharge() 搬移到AccountType 类去。

第一步要作的是:观察被overdraftCharge()使用的每一项特性,考虑是否值得将它们与overdraftCharge() 一块儿移动。此例中,咱们须要让daysOverdrawn字段留在Account类,由于这个值不会随不一样种类的帐户而变化。而后,咱们将overdraftCharge()函数复制到AccountType中,并作相应调整。

public class AccountType
{
    double overdraftCharge( int daysOverdrawn )
    {
        if( isPremium() )
        {
            double result = 10;
            if( daysOverdrawn > 7 )
            {
                result += ( daysOverdrawn - 7 ) * 0.85;
                return result;
            }
        }
        else
        {
            return daysOverdrawn * 1.75;
        }
        return 0;
    }
}
调整目标函数使之经过编译,然后就能够将源函数的函数本体替换为一个简单的委托动做,而后编译测试。

public class Account
{
    private AccountType type;

    private int daysOverdrawn;

    double overdraftCharge()
    {
        return type.overdraftCharge( daysOverdrawn );
    }
...
}
咱们能够保留代码如今的样子,也能够删除源函数。若是决定删除,就得找出源函数的全部调用者,并将这些调用从新定向,改成调用Account的overdraftCharge().

在全部的调用点都修改完毕后,就能够删除源函数在Account中的声明了。若是被搬移的函数不是private的,还要检查其余类是不是用了这个函数。

此例中被搬移的函数只引用了一个字段,因此只须要将这个字段做为参数传给目标函数就好了。若是被搬移的函数调用了Account中的另外一个函数,就不能这么简单的处理。这种状况下必须将源对象传递给目标函数。

若是须要源类的多个特性,那么咱们也能够将源对象传递给目标函数。不过若是目标函数须要太多源类特性,就得进一步重构。一般这种状况下,咱们须要分解目标函数,并将其中一部分移回源类。

相关文章
相关标签/搜索