小结_01:《重构:改善既有代码的设计》
来源:互联网 发布:两台nginx做负载均衡 编辑:程序博客网 时间:2024/05/16 13:02
重构的意义: 你永远不必说对不起————只要把出问题的地方修补好就行了。
以下小结各种重构技巧
Part I : 重构技术的基础之一:在对象之间搬移特性
( 涉及概念: Method; Field; Class; Delegate; Middle Man; Foreign Method; Local Extension)
一. 搬移方法:
实施的条件: 如果一个类有很多方法,或者一个类与另一个类有太多合作而形成高度耦合;那么考虑搬移方法
(代码坏味道: 使用另一个对象的次数比使用自己所驻对象的次数还多。)
实施结果: 系统变得更加的清晰。
操作的注意事项:
1. 在将目标函数从源类中移到目标类中去了之后,可以直接去掉源函数,或者将其变成“委托函数”,(如下就是一个委托函数):
class Account... double getFee(){ return _transaction.getFee(_daysOfRent); }
2.如果移除了源函数的话,在强类型的语言中,编译器会帮助我发现任何“调用源函数”方面的遗漏。
3.如果被搬移的函数使用了多个源类中的字段,那么应该将源类的对象作为参数传递给这个函数的调用;
但是,如果这些字段过多的话,理应在“搬移方法”之前就将目标函数分解,将其中的一部分保留在源类当中。
二. 搬移字段:
实施的条件:对于一个字段,在其所驻类之外的另一个类中有更多函数使用了它,就应该考虑搬移这个字段。
操作注意事项:
1. 如果字段的访问级别是public级,就应该把它“自封装”起来:
(意思就是,对这个字段设计set和get方法)
或者,即使该字段的级别是private级别的,但是有多个函数在访问它,那么也应该“自封装”
三. 对Class的处理:
3.1 提取新类:
类是不断地会被修改和变化的;
如果某些数据和某些函数总是一起出现,某些数据经常同时变化甚至彼此相依,就是应该将它们分离出去的时候了。
如果类中有两部分或多部分特性需要不同的子类化策略,那么也需要提取新类;
注意事项:
a. 必须考虑需不需要向外公布新类;
如果不公布,那么新类中的函数将全部被委托至旧类;
如果公布, 而且允许任何人修改属性,那么必须使得新类的对象成为“引用对象”(即用工厂方法控制该类对象的创建)
3.2 内联类:
如果一个类没有做太多的事情, 那么需要“将这个类搬移到其他的类”,即使之内联化:
操作注意事项:
a. 先要在目标类中建立对所有源类public函数的“委托”;再修改所有对源类函数的调用点;最后放心大胆地把源类特性全部搬到目标类中。
3.3 委托关系:
尽量隐藏委托关系;(不希望客户深入了解是如何委托的,只需要调用接口中的函数就行了)
做法: 首先对于服务模块中的每一个委托关系中的函数,都在服务对象端(Client端)建立一个简单的委托函数。
但是,如果某个类里面全是委托关系,这个服务类变成了一个“中间人”,那么可以让客户直接调用受委托类(即“移除中间人类”)
3.4 Local Extension:
如果需要为服务类提供一些额外函数,但是无法修改这个类的时候,需要建立一个子类来扩展这个类,把这些函数添加到子类当中去。
Part II: 其他技巧
一:重构当中最具观赏性的工作: “以多态取代条件表达式”:
现象: 如果case 条件中的字段分属于不同的子类对象,那么就可以使用多态了
操作如下:
1. 在子类中建立同样的函数,分别执行case中设定的逻辑;
2. 为这些子类的超类(如果没有就建立一个)构造一个同名抽象函数;
3. 在调用端使用委托的方式调用超类中的抽象函数。
与条件表达式相关的技术还有:“以卫语句取代条件表达式”:
动机:函数中的条件逻辑使人难以看清正常的执行路径
但是,条件表达式通常有两种表现形式, 第一:所有分支都属于正常行为。 第二:条件表达式提供的答案中只有一种是正常行为,其他的都是不常见的行为。
对于第二种情况,就应该单独检查该条件,并在该条件为真时立即从函数中返回。这样的单独检查常常被称为“卫语句”(guard clause),效果如下:
double getPayAmout(){ if(_isDead) return deadAmout(); if(_isSepatated) return separatedAmount(); if(_isRetired) return retiredAmout(); return normalPayAmount(); }
二: 优化函数
a)将查询函数和修改函数分离:
优化函数有一条好规则就是:任何有返回值的函数,都不应该有看得到的副作用
如果一个函数修改了值又返回,那么在其他的地方调用它就会不那么放心;
注意事项:在多线程编程中,经常需要在同一个动作中完成查询和赋值;
如果要追求更好的函数表现,我会将查询和赋值分开来,同时使用一个synchronized修饰的函数取代原来的动作并调用这两个“查询”和“赋值”的函数。
b)以工厂函数取代构造函数:
使用这个方法的动机在于,避免根据类型码来创建相应的对象,即避免将子类名称暴露给用户。
操作步骤:
1. 新建一个工场函数,使用工厂函数调用现有的构造函数
2. 将调用构造函数的代码换为调用工厂函数。
3. 将构造函数声明为private;
接下来一般还要继续做的是“将类型码替换为子类”, 在新的工场函数里面完成对不同子类对象的创建;这一般会产生一个switch语句。
如果要绕过这种switch语句,一个好办法就是使用Class.forName()。比如下面一段代码:
static Employee create(int type){ switch(type){ case ENGINEER: return new Engineer(); case SALESMAN: return new Salesman(); case MANAGER: return new Manager(); default: throw new IllegalArgumentException("Incorrect type code value"); } }
经过一系列操作以后,可以变化为如下形式:
static Employee create(String name){ try{ return (Employee) Class.forName(name).newInstance(); } catch(Exception e) { throw new IllegalArgumentException("Unable to instantiate" + name); } }
- 小结_01:《重构:改善既有代码的设计》
- 小结_02:《重构:改善既有代码的设计》
- 重构-改善既有代码的设计
- 重构-改善既有代码的设计
- 重构-改善既有代码的设计
- 重构-改善既有代码的设计
- 重构:改善既有代码的设计
- 重构--改善既有代码的设计
- 重构-改善既有代码的设计
- 重构-改善既有代码的设计
- 重构-改善既有代码的设计+
- 重构--改善既有代码的设计
- 重构 改善既有代码的设计
- 重构.改善既有代码的设计
- 重构:改善既有代码的设计
- 重构,改善既有代码的设计
- 重构改善既有代码的设计
- 重构-改善既有代码的设计
- 龙年即将过去!
- Linux 线程实现机制分析
- 将任一整数转换为二进制形式
- HibernateTemplate类的使用
- 开放式地图制图课程——OGC学习秘籍
- 小结_01:《重构:改善既有代码的设计》
- asp.net中的datarow
- POJ1860,Currency Exchange,最近懒死了啊,,,
- Java异常处理的陋习展播
- 感悟--消冗,解耦
- Jquery操作数组元素(三)字符串数组与数值数组的排序
- vmware workstation + kvm + ubuntu 12.04 + openstack(folsom)环境搭建
- 【Android】挺好用的chart engine,可用于Android画饼图,条形图等
- 设计模式2 - 抽象工厂模式AbstractFactory Method