范例(Examples)
我用一个表示[帐户]的account class来说明这项重构:
class Account...
double overdraftCharge() { //透支金计费,它和其他class的关系似乎比较密切。
if(_type.isPremium()) {
double result = 10;
if(_daysOverdrawn > 7)
result += (_daysOverdrawn -7) * 0.85;
return result;
}
else return _daysOverdrawn * 1.75;
}
double bankCharge() {
double result = 4.5;
if(_daysOverdrawn > 0) result += overdraftCh你arge();
return result;
}
private AccountType _type;
private int _daysOverdrawn;
假设有数种新帐户,每一种都有自己的[透支金计费规则]。所以我希望将overdraftCharge()搬移到AccountType class去。
第一步要做的是:观察被overdraftCharge()使用的每一特性(features),考虑是否值得将它们与overdraftCharge()一起移动。此例之中我需要让_daysOverdrawn值域留在Account class,因为其值会随不同种类的帐户而变化。然后,我将overdraftCharge()函数码拷贝到AccountType中,并做相应调整。
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;
}
在这个例子中,[调整]的意思是:(1)对于[使用AccountType特性]的语句,去掉──type;(2)想办法得到依旧需要的Account
class特性。当我需要使用source class特性,我有四种选择:(1)将这个特性也移到target
class;(2)建立或使用一个从target class到source的引用(指涉)关系;(3)将source
object当作参数传给target method;(4)如果所需特性是个变量,将它当作参数传给target method。
本例中我将_daysOverdrawn变量作为参数传给target method(上述(4))。
调整target method使之通过编译,而后我就可以将source method的函数本体替换为一个简单的委托动作(delegation),然后编译并测试:
class Account...
double overdraftCharge() {
return _type.overdraftCharge(_daysOverdrawn);
}
我可以保留代码如今的样子,也可以删除source method。如果决定删除,就得找出source method的所有调用者,并将这些调用重新定向,改调用Account的bankCharge():
bankCharge():
class Account...
double bankCharge() {
double result = 4.5;
if(_daysOverdrawn > 0)
result += _type.overdraftCharge(_daysOverdrawn);
return result;
}
所有调用点都修改完毕后,我就可以删除source
method在Account中的声明了。我可以在每次删除之后编译并测试,也可以一次性批量完成。如果被搬移的函数不是private,我还需要检查其
他classes是否使用了这个函数。在强型(strongly typed)语言中,删除source
method声明式后,编译器帮我发现任何遗漏。
此例之中被移函数只取用(指涉)一个值域,所以我只需将这个值域作为参数传给target method就行了。如果被移函数调用了Account中的另一个函数,我就不能这么简单地处理。这种情况下我必须将source object传递给target method:
class AccountType...
double overdraftCharge(Account account) {
if(isPremium()) {
double result = 10;
if(account.getDaysOverdrawn() >7)
result += (account.getdaysOverdrawn() - 7) * 0.85;
return result;
}
else return daysOverdrawn * 1.75;
}
如果我需要source class的多个特性,那么我也会将source object传递给target method。不过如果target
method需要太多source class特性,就得进一步重构。通常这种情况下我会分解target
method,并将其中一部分移回source class。