1. 搬移函数(Move Method)
1.1 动机
(1)某函数与其所驻类之外的另一个类进行更多交流(调用后者或被后者调用),这时可以在后者中建立一个类似行为的新函数。将旧函数变成一个委托函数或将其完全移除。
(2)当类中存在这样的函数:使用另一个对象的次数比使用自己所驻对象的次数还多,这时可以考虑将函数搬移到另一个对象中。
1.2 做法
(1)检查源类中被源函数所使用的一切特性(包括字段和函数),考虑它们是否也该被搬移。如果某个特性只被你打算搬移的那个函数用到,就应该将它一并搬移。如果另有其他函数使用了这个特性,可以考虑将使用该特性的所有函数全都一并搬移。
(2)检查源类中的子类或父类,看看是否有该函数的其他声明。如果出现其他声明,可能就无法进行搬移,除非目标类也同样表现出多态性。
(3)在目标类中声明这个函数(可以为此函数选择一个新名称)
(4)将源函数的代码复制到目标函数中。调整后者,使用能在新的类中正常运行。如果目标函数使用了源类中的特性,可以将源对象当作参数,传递给新的目标函数。
(5)决定如何从源函数正确引用目标对象。(如,可在源类中新建一个字段来保存目标对象)
(6)修改源函数,使之成为一个纯委托函数。
(7)决定是否删除源函数,或将它当作一个委托函数保留下来。如果要移除源函数,还得将源类中所有对源函数的调用,替换为对目标函数的调用。
1.3 范例
//搬移函数 //重构前 class Account { private: AccountType _type; //账户类型 int _daysOverdrawn; public: //每种账户都有自己的“透支金额计费规则”,该函数可 //被搬移到AccoutType类中去。 double overdraftCharge() { if(_type.isPremium()) { double result = 10; if(_daysOverdrawn > 7) result += (_daysOverdrawn - 7) * 0.85; return result; } else { return _daysOverdrawn * 1.75; } } }; //重构中 //1. 观察overdraftCharge()使用的每一项特性,考虑是否将它们与 //该函数一起被搬移。本例中_daysOverdrawn不会随不同种类账户而变化 //可留在Account类中。 //2.i当需要使用源类的特性时,有4种选择: //(1)将这个特性也移到目标类 //(2)建立或使用一个从目标类到源类的引用关系。 //(3)将源对象当作参数传给目标函数 //(4)如果所需特性是个变量,将它当作参数传给目标函数。 //重构后 class Account... { public: //该函数可以用委托方式来代替,也可以删除(但必须同时修改所有对该函数的引用点) double overdraftCharge() { return _type.overdraftCharge(_daysOverdrawn); //委托方式 } }; class AccoutType... { public: //使用到源函数中的特性daysOverdrawn,这里将其作为参数传递给目标函数。 double overdraftCharge(int daysOverdrawn) { if(isPremium()) { double result = 10; if(daysOverdrawn > 7) result += (daysOverdrawn - 7) * 0.85; return result; } else { return daysOverdrawn * 1.75; } } };
2. 搬移字段(Move Field)
2.1 动机
(1)某个字段被其所驻类之外的另一个类更多地使用到,可以在目标类新建一个字段,修改源字段的所有用户,令它们改用新字段。上述所谓“使用”可以是通过get/setter函数间接进行的。
(2)使用Extract Class时,也可能需要搬移字段,此时可以先搬移字段,然后再搬移函数。
2.2 做法
(1)如果字段的访问级是public,使用Encapsulate Field将它封装起来。
(2)在目标类中建立与源字段相同的字段,并同时建立相应的设值/取值函数。
(3)决定如何在源对象中引用目标对象。在源类中建一个字段来保存目标对象。
(4)删除源字段,将所有对源字段的引用替换为某个目标函数的调用。
2.3 范例
//搬移字段 //重构前 class Account... { private: AccountType _type; double _interestRate; //要搬移的字段 public: //引用了_interestRate字段的函数 double interestForAmount_days(double amount, int days) { return _interestRate * amount * days / 365; } }; //重构后 class Account... { private: AccountType _type; double _interestRate; //如果有多个函数引用了该字段可以用 //Self-Encapsulation封装起来 //对_interestRate进行封装 void setInterestRate(double arg) { _type.setInterestRate(arg); } double getInterestRate(arg) { return _type.getInterestRate(); } public: //引用了_interestRate字段的函数,使用getInterestRate替代 double interestForAmount_days(double amount, int days) { return getInterestRate * amount * days / 365; } }; class AccoutType... { private: double _interestRate; public: //新建设值/取值函数 void setInterestRate(double arg) { _interestRate = arg; } double getInterestRate() { return _interestRate; } };