Move Field(搬移值域)

你的程序中,某个field(值域)被其所驻class之外的另一个class更多地用到。

在target class建立一个new field,修改source field的所有用户,令它们改用new field。

 

class class1

{

    private int aField;

}

class class2{}

 

==>

class class1

{}

class class2

{

 private int aField;

}

 

动机

 

如果我发现,对于一个field(值域),在其所驻class之外的另一个class中有更多函数使用了它,我就会考虑搬移这个field。上述所谓[使用]可能通过设值/取值(setting/getting)函数间接进行。我也可能移动该field的用户(某函数),这取决于是否需要保持接口不受变化。如果这些函数看上去很合适待在原地,我就选择搬移field。

使用Extract Class(149)时,我也可能需要搬移field。此时我会先搬移field,然后再搬移函数。

 

作法

 

1. 如果field的属性是public,首先使用Encapsulate Field(206)将它封装起来。

如果你有可能移动那些频繁访问该field的函数,或如果有许多函数访问某个field,先使用Self Encapsulate Field(171)也许会有帮助。

2. 编译,测试。

3. 在target class中建立与source field相同的field,并同时建立相应的设值/取值(setting/getting)函数。

4. 编译target class。

5. 决定如何在source object中引用target object。

6. 一个现成的field或method可以助你得到target object。如果没有,就看能否轻易建立这样一个函数。如果还不行,就得在source class中新建一个field来存放target object。这可能是个永久性修改,但你也可以暂不公开它,因为后续重构可能会把这个新建field除掉。

7. 删除source field。

8. 将所有[对source field的引用]替换为[对target适当函数的调用]。

如果是[读取]该变量,就把[对source field的引用]替换为[对target取值函数(getter)的调用];如果是[赋值]该变量,就把[对source field的引用]替换成[对设值函数(setter)的调用]。

如果source field不是private,就必须在source class的所有subclasses中查找source field的引用点,并进行相应替换。

9. 编译,测试。

下面是Account class的部分代码:
class Account...
    private AccountType _type;
    private double _interestRate;
    double interestForAmount_days(double amount, int days) {
       return _interestRate * amount * days / 365;
    }

 

我想把表示利率的_interestRate搬移到AccountType class去。目前已有数个函数引用了它,interestForAmount_days()就是其一。下一步我要在AccountType中建立_interestRate field以及相应的访问函数:
class AccountType...
    private double _interestRate;

    void setInterestRate(double arg) {
       _interestRate = arg;
    }
    double getInterestRate() {
       return _interestRate;
    }

 

这时候我可以编译新的 AccountType class。
现在,我需要让Account class中访问_interestRate field的函数转而使用AccountType对象,然后删除Account class中的_interestRate field。我必须删除source field,才能保证其访问函数的确改变了操作对象,因为编译器会帮我指出未正确获得修改的函数。

class Account...
    private double _interestRate;
    double interestForAmount_days(double amount, int days) {
       return _type.getInterestRate() * amount * days / 365;
    }

 

如果有很多函数已经使用了_interestRate field,我应该先运用Self Encapsulate Field(171):

class Account...
    private AccountType _type;
    private double _interestRate;
    double interestForAmount_days(double amount, int days) {
       return getInterestRate() * amount * days / 365;
    }
    private void setInterestRate(double arg) {
       _interestRate = arg;
    }
    private double getInterestRate() {
       return _interestRate;
    }

 

这样,在搬移field之后,我就只需要修改访问函数就行了:

    double interestForAmount_days(double amount, int days) {
       return getInterestRate() * amount * days / 365;
    }
    private void setInterestRate(double arg) {
       _type.setInterestRate(arg);
    }
    private double getInterestRate() {
       return _type.getInterestRate();
    }

 

如果以后有必要,我可以修改访问函数(accessors)的用户,让它们使用新对象。Self Encapsulate Field(171)使我得以保持小步前进。如果我需要对class做许多处理,保持小步前进是有帮助的。特别值得一提的是:首先使用Self Encapsulate Field(171)使我得以更轻松使用Move Method(142)将函数搬移到target class中。如果待移函数引用了field的访问函数(accessors),那么那些引用点是无须修改的。


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值