重构改善既有代码设计--重构手法11:Move Field (搬移字段)
你的程序中,某个字段被其所驻类之外的另一个类更多的用到。在目标类建立一个新字段,修改源字段的所有用户,令它们改用新字段。
动机:在类之间移动状态和行为,是重构过程中必不可少的措施。随着系统发展,你会发现自己需要新的类,并需要将现有的工作责任拖到新的类中。在这个星期看似合理而正确的设计决策,到了下个星期可能不再正确。这没问题,如果你从来没遇到这种情况,那才有问题。
如果发现对于一个字段,在其所驻类之外的另一个类中有更多函数使用了它,就考虑搬移这个字段。上述所谓“使用”可能是通过设值/取值函数间接进行的。也可能移动该字段的用户(某个函数),这取决于是否需要保持接口不受变化。如果这些函数看上去很适合待在原地,就选择搬移字段。
使用Extract Class (提炼类)时,也可能需要搬移字段。此时可以先搬移字段,然后搬移函数。
做法:1、如果字段的访问级别是public,使用 Encapsulated Field (封装字段)将它们封装起来。如果你有可能移动那些频繁访问该字段的函数,或如果有许多函数访问某个字段,先使用 Self Encapsulate Field (自封装字段)也许会有帮助。
2、编译、测试。
3、在目标类中建立于源字段相同的字段,并同时建立相应的设值/取值函数。
4、编译目标类。
5、决定如何在源对象中引用目标对象。首先看是否有一个现成的字段或函数可以助你得到目标对象。如果没有,就看能否轻易建立这样一个函数。如果还不行,就得在源类中新建一个字段来存放目标对象。这可能是个永久性修改,但你也可以让它是暂时的。因为后续重构可能会把这个新建字段除掉。
6、删除源字段。
7、将所有对源字段的引用替换为某个目标函数的调用。如果需要读取该变量,就把对源字段的引用替换为对设值函数的调用。如果源字段不是private的,就必须在源类的所有子类中查找源字段的引用点,并进行相应替换。
8、编译、测试。
下面是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),那么那些引用点是无须修改的。
重构改善既有代码设计--重构手法11:Move Field (搬移字段)的更多相关文章
- 重构改善既有代码设计--重构手法13:Inline Class (将类内联化)
某个类没有做太多事情.将这个类的所有特性搬移到另一个类中,然后移除原类. 动机:Inline Class (将类内联化)正好于Extract Class (提炼类)相反.如果一个类不再承担足够责任.不 ...
- 重构改善既有代码设计--重构手法12:Extract Class (提炼类)
某个类做了应该由2个类做的事.建立一个新类,将相关的字段和函数从旧类搬移到新类. 动机:一个类应该是一个清楚地抽象,处理一些明确的责任.但是在实际工作中,类会不断成长扩展.你会在这儿加入一些功能,在哪 ...
- 重构改善既有代码设计--重构手法16:Introduce Foreign Method (引入外加函数)&& 重构手法17:Introduce Local Extension (引入本地扩展)
重构手法16:Introduce Foreign Method (引入外加函数)你需要为提供服务的类增加一个函数,但你无法修改这个类.在客户类中建立一个函数,并以第一参数形式传入一个服务类实例. 动机 ...
- 重构改善既有代码设计--重构手法10:Move Method (搬移函数)
你的程序中,有个函数与其所驻类之外的另一个类进行更多的交流:调用后者,或被后者调用.在该函数最常用引用的类中建立一个有着类似行为的新函数.将旧函数编程一个单纯的委托函数,或是将旧函数完全移除. 动机: ...
- 重构改善既有代码设计--重构手法08:Replace Method with Method Object (以函数对象取代函数)
你有一个大型函数,其中对局部变量的使用,使你无法釆用 Extract Method. 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域(field) 然后你可以在同一个对象中将这个大型 ...
- 重构改善既有代码设计--重构手法07:Remove Assignments to Parameters (移除对参数的赋值)
代码对一个 参数赋值.以一个临时变量取代该参数的位置. int Discount(int inputVal, int quantity, int yearTodate) { if (input ...
- 重构改善既有代码设计--重构手法05:Introduce Explaining Variable (引入解释性变量)
发现:你有一个复杂的表达式. 解决:将该复杂的表达式(或其中的部分)的结果放进一个临时变量,并以此变量名称来解释表达式用途. //重构前 if((platform.toUpperCase().in ...
- 重构改善既有代码设计--重构手法04:Replace Temp with Query (以查询取代临时变量)
所谓的以查询取代临时变量:就是当你的程序以一个临时变量保存某一个表达式的运算效果.将这个表达式提炼到一个独立函数中.将这个临时变量的所有引用点替换为对新函数的调用.此后,新函数就可以被其他函数调用. ...
- 重构改善既有代码设计--重构手法02:Inline Method (内联函数)& 03: Inline Temp(内联临时变量)
Inline Method (内联函数) 一个函数调用的本体与名称同样清楚易懂.在函数调用点插入函数体,然后移除该函数. int GetRating() { return MoreThanfiveLa ...
随机推荐
- MacBook Pro 15寸常见问题及修复
苹果MacBook Pro更换SSD硬盘攻略教程 MacBook pro开机黑屏解决 苹果电脑 MAC PRO 开机黑屏了 MacBook Pro 开机后黑屏,怎么办啊 如果 Mac 无法开机 Mac ...
- Traffic Steering for Service Function Chaining
Introduction 目前通过vlan标签来把流量引向对应的sfc 以前的sfc静态(SFs相邻组成SFC),有了sdn之后具有动态性.(SFs不需要彼此相邻.将流量动态地导向所需的SFs.) 流 ...
- Eclipse 如何安装反编译插件
安装反编译插件 1.Help——Eclipse Marketplace 2.输入 Decompiler 搜索并安装此插件 3.根据提示无脑下一步,安装好,重启后(如果还是无法编译,需要把默认打开cla ...
- 小程序获取 openid 和 session_key
<?php //获取openid function getopenid(){//获取用户ID //code为前端通过 wx.login() 方式获取 $code = $_GET["co ...
- linux svn启动和关闭
linux svn启动和关闭 博客分类: linux系统 svnlinux 1,启动SVN sudo svnserve -d -r /home/data/svn/ 其中 -d 表示守护进程, -r ...
- MyEclipse+SSH开发环境配置
MyEclipse+Struts+Hibernate+Mysql开发环境配置 软件: jdk-6u22-windows-x64.exe apache-tomcat-6.0.29.exe mysql-5 ...
- Linux服务器启动后只读解决办法
今天处理一个服务器,远程死活连接不上,只好跑信息中心去看了下服务器. Linux服务器启动之后,提示: give root password for maintenance (or type cont ...
- javascriptDOM编程
DOM - Document Object Model,它是W3C国际组织的一套Web标准,它定义了访问HTML文档对象的一套属性,方法和事件. <html> <head> & ...
- postman 上一个接口返回值传给下一个接口
问题:如何将A请求responseBody中的token传入B请求中的request中 把A请求中的token设置为环境变量,如下: tests["Status code is 200&qu ...
- day 008 文件操作
08. 万恶之源-⽂文件操作本节主要内容:1. 初识⽂文件操作2. 只读(r, rb)3. 只写(w, wb)4. 追加(a, ab)5. r+读写6. w+写读7. a+写读(追加写读)8. 其他操 ...