在对象之间搬移特性之一 :Move Method(搬移函数)
来源:互联网 发布:淘宝保证金在哪里 编辑:程序博客网 时间:2024/06/10 20:56
你的程序中,有个函数与其所驻class之外的另一个class进行更多交流:调用后者,或被后者调用。
在该函数最常引用(指涉)的class中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托函数(delegating method),或是将旧函数完全移除。
动机(Motivation)
「函数搬移」是重构理论的支柱。如果一个class有太多行为,或如果一个class与另一个class有太多合作而形成高度耦合(highly coupled),我就会搬移函数。通过这种手段,我可以使系统中的classes更简单,这些classes最终也将更干净利落地实现系统交付的任务。
常常我会浏览class的所有函数,从中寻找这样的函数:使用另一个对象的次数比使用自己所驻对象的次数还多。一旦我移动了一些值域,就该做这样的检查。一旦发现「有可能被我搬移」的函数,我就会观察调用它的那一端、它调用的那一端,以及继承体系中它的任何一个重定义函数。然后,我会根据「这个函数与哪个对象的交流比较多」,决定其移动路径。
这往往不是一个容易做出的决定。如果不能肯定是否应该移动一个函数,我就会继续观察其他函数。移动其他函数往往会让这项决定变得容易一些。有时候,即使你移动了其他函数,还是很难对眼下这个函数做出决定。其实这也没什么大不了的。 如果真的很难做出决定,那么或许「移动这个函数与否」并不那么重要。所以,我会凭本能去做,反正以后总是可以修改的。
作法(Mechanics)
范例(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 += overdraftCharge();
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 returndaysOverdrawn * 1.75;
}
在这个例子中,「调整」的意思是:(1)对于「使用AccountType特性」的语句,去掉_type;(2)想办法得到依旧需要的Account class特性。当我需要使用source class特性,我有四种选择:(1)将这个特性也移到target class;(2)建立或使用一个从target class到source的引用〔指涉)关系;(3)将source object当作参数传给target class;(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():
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 account.getDaysOverdrawn() * 1.75;
}
如果我需要source class的多个特性,那么我也会将source object传递给target method。不过如果target method需要太多source class特性,就得进一步重构。通常这种情况下我会分解target method,并将其中一部分移回source class。
- 在对象之间搬移特性之一 :Move Method(搬移函数)
- 在对象之间搬移特性---搬移函数
- 在对象之间搬移特性之二 :Move Field(搬移值域)
- Move Method(搬移函数)
- 在对象之间搬移特性之七 :Introduce Foreign Method(引入外加函数)
- 在对象之间搬移特性(一)
- 在对象之间搬移特性(二)
- 在对象之间搬移特性
- 7.1 move method (搬移函数)
- 《Refactoring》,Move Method(搬移函数)
- 第七章 在对象之间搬移特性
- 3、在对象之间搬移特性
- 第七章 在对象之间搬移特性
- 7. 在对象之间搬移特性
- 重构之在对象之间搬移特性
- 重构系列4.在对象之间搬移特性
- 重构摘要7_在对象之间搬移特性
- 在对象之间搬移特性---Hide Delegate(隐藏委托关系)
- 字符串匹配的KMP算法
- 程序员,如何从多个工作机会中做出选择?
- cleanpyc: Running find /home/liu/Desktop/// -iname '*.pyc' -delete
- 合格程序员七大基本素质与五大必备能力
- sqlite3的数据操作
- 在对象之间搬移特性之一 :Move Method(搬移函数)
- IT人“升级”四大选择
- Java如何实现多态性,基于itable, vtable源码分析
- 利用WM_GETTEXT消息获取谷歌浏览器地址栏内容。
- TopCoder SRM578 Div.2
- 修改JAVA_HOME无效,java版本保持不变的问题解决
- Perl实现后台守护进程
- Linux 内存管理 -- 线性空间与物理内存
- 在对象之间搬移特性之二 :Move Field(搬移值域)