封装

封装字段、封装记录(数据)、封装函数、封装类

封装记录(Encapsulate Record)

title content
场景 多个可变数据在多个地方使用
意义  
定义  
做法  
注意 封装大型的数据结构时,我会更多关注更新操作。凸显更新操作,并将它们集中到一处地方,是此次封装过程最重要的一部分。

封装集合(Encapsulate Collection)

title content
场景  
意义  
定义  
做法  
注意 但封装集合时人们常常犯一个错误:只对集合变量的访问进行了封装,但依然让取值函数返回集合本身。
这使得集合的成员变量可以直接被修改,而封装它的类则全然不知,无法介入。

为避免此种情况,我会在类上提供一些修改集合的方法——通常是"添加"和"移除"方法。
这样就可使对集合的修改必须经过类,当程序演化变大时,我依然能轻易找出修改点。

不要让集合的取值函数返回原始集合,这就避免了客户端的意外修改。

提炼类(Extract Class)

| title | content | | —- | —- | | 场景 | 如果你发现子类化只影响类的部分特性,或如果你发现某些特性需要以一种方式来子类化,某些特性则需要以另一种方式子类化,这就意味着你需要分解原来的类。 | | 意义 | | | 定义 | | | 做法 | 决定如何分解类所负的责任。
创建一个新的类,用以表现从旧类中分离出来的责任。
如果旧类剩下的责任与旧类的名称不符,为旧类改名。

构造旧类时创建一个新类的实例,建立"从旧类访问新类"的连接关系。
对于你想搬移的每一个字段,运用【搬移字段】搬移之。每次更改后运行测试。
使用【搬移函数】将必要函数搬移到新类。先搬移较低层函数(也就是"被其他函数调用"多于"调用其他函数"者)。每次更改后运行测试。
检查两个类的接口,去掉不再需要的函数,必要时为函数重新取一个适合新环境的名字。
决定是否公开新的类。如果确实需要,考虑对新类应用【将引用对象改为值对象】使其成为一个值对象。 | | 注意 | |

内联类(Inline Class)

title content
场景 一个类不再承担足够责任,不再有单独存在的理由(这通常是因为此前的重构动作移走了这个类的责任)
意义  
定义 挑选这一"萎缩类"的最频繁用户(也是一个类),以本手法将"萎缩类"塞进另一个类中
做法 对于待内联类(源类)中的所有public函数,在目标类上创建一个对应的函数,新创建的所有函数应该直接委托至源类。
修改源类public方法的所有引用点,令它们调用目标类对应的委托方法。每次更改后运行测试。
将源类中的函数与数据全部搬移到目标类,每次修改之后进行测试,直到源类变成空壳为止。
删除源类,为它举行一个简单的"丧礼"
注意 有时把相关元素一口气搬移到位更简单,但有时先用内联手法合并各自的上下文,再使用提炼手法再次分离它们会更合适。

替换算法(Substitute Algorithm)

Tip

使用这项重构手法之前,我得确定自己已经尽可能分解了原先的函数。

title content
场景  
意义  
定义  
做法 整理一下待替换的算法,保证它已经被抽取到一个独立的函数中。
先只为这个函数准备测试,以便固定它的行为。
准备好另一个(替换用)算法。
执行静态检查。
运行测试,比对新旧算法的运行结果。如果测试通过,那就大功告成;否则,在后续测试和调试过程中,以旧算法为比较参照标准
注意