重构概述
重构—对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
?
代码坏味道
常用重构手段
Duplicated重复代码
Extract Method
Extract Class
Pull Up Method
Form Template Method
Long Method 过长函数
Extract Method
Replace Temp With Query
Replace Method With Method Object
Decompose Conditional
Large Class 过大的类
Extract Class
Extract Subclass
Extract Interface
Replace Data Value With Object
Long Parameter List 过长参数列
Replace Parameter With Method
Introduce Parameter Object
Preserve Whole Object
Divergent Change 发散式变化
Extract Class
Shotgun Surgery散弹式修改
Move Method
Move Field
Inline Class
Feature Envy 依恋情结
Move Method
Move Field
Extract Method
Data Clumps 数据泥团
Extract Class
Introduce Parameter Object
Preserve Whole Object
Primitive Obsession 基本类型偏执
Replace Data Value With Object
Extract Class
Introduce Parameter Object
Replace Array with Object
Replace Type Code With Class
Replace Type Code With Subclasses
Replace Type Code With State/Strategy
Switch Statements switch惊悚现身
Replace Conditional With Polymorphisrn
Replace Type Code With Subclasses
Replace Type Code With State/Strategy
Replace Parameter With Explicit Methods
Introduce Null Object
Parallel Inheritance Hierarchies 平行继承体系
Move Method
Move Field
Lazy Class 冗赘类
Inline Class
Collapse Hierarchy
Speculative Generality 夸夸其谈未来性
Collapse Hierarchy
Inline Class
Remove Parameter
Rename Method
Temporary Field 令人迷惑的暂时字段
Extract Class
Introduce Null Object
Message Chains 过度耦合的消息链
Hide Delegate
Middle Man 中间人
Remove Middle Man
Inline Method
Replace Delegation With Inheritance
Inappropriate Intimacy 狎昵关系
Move Method
Move Field
Change Bidirectional Association to Unidirectional
Replace Inheritance With Delegation
Hide Delegate
Alternative Classes with Different Interfaces 异曲同工的类
Rename Method
Move Method
Incomplete Library Class 不完美的库类
Introduce Foreign Method
Introduce Local Extension
Data Class 纯稚的数据类
Move Method
Encapsulate Field
Encapsulate Colletion
Refused Bequest 被拒绝的遗赠
Replace Inheritance With Delegation
Comments 过多的注释
Extract Method
Introduce Assertion
?
重构列表:
有一段代码可以被组织在一起并独立出来
将这段代码放进一个独立函数中,并让函数名称解释该函数的用途
一个函数,其本地应该与其名称同样清楚易懂
在函数调用点插入函数本地,然后移除该函数
有一个变量,只被一个简单表达式赋值一次,而它妨碍了其他重构手法
将所有对该变量的引用动作,替换为对它赋值的那个表达式本身
程序以一个临时变量保存某一表达式的运算结果
将这个表达式提炼到一个独立函数中,将这个临时变量的所有被引用点替换为对新函数的调用。新函数可被其他函数使用
有一个复杂的表达式
将该表达式(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途
程序有某个临时变量被赋值超过一次,它既不是循环变量,也不是一个集用临时变量
针对每次赋值,创造一个独立的、对应的临时变量
代码对一个参数进行赋值动作
以一个临时变量取代该参数的位置
有一个大型函数,其中对局部变量的使用,使得无法采用Extract Method
将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域,然后可以再同一个对象中将这个大型函数分解为数个小型函数
把某个算法替换为另一个更清晰的算法
将函数本体替换为另一个算法
在程序中,有个函数与其所驻class之外的另一个class进行更多交流:调用后者,或被后者调用
在程序中,某个field被其所驻class之外的另一个class更多地用到
在target class建立一个new field,修改source field的所有用户,令它们改用此new field
某个class做了应该由两个classes做的事
建立一个新class,将相关的值域和函数从旧class搬移到新class
某个class没有做太多的事情(没有承担足够责任)
将class的所有特性搬移到另一个class中,然后移除原class
客户直接调用其server object的delegate class
在server端建立客户所需的所有函数,用以隐藏委托关系
某个class做了过多的简单委托动作
让客户直接调用delegate
所使用的server class需要一个额外函数,但无法修改这个class
在client class中建立一个函数,并以一个server class实体作为第一参数
使用的server class需要一些额外函数,但无法修改这个class
建立一个新class,使它包含这些额外函数。让这个扩展品成为source class的subclass或wrapper
直接访问一个field,但与值域之间的耦合关系逐渐变得笨拙
为这个值域建立取值/设置函数,并且只以这些函数来访问值域
有一笔数据项(data item),需要额外的数据和行为
将这笔数据项变成一个对象
有一个class,衍生出许多相等尸体,希望将它们替换为单一对象
将这个value object变成一个reference object
有一个reference object,很小且不可变,而且不易管理
将它变成一个value object
有一个数组,其中的元素各自代表不同的东西
以对象替换数组。对于数组中的每个元素,以一个值域表示之
有一些domain class置身于GUI控件中,而domain method需要访问之
将改笔数据拷贝到一个domain object中。建立一个Observer模式,用以对domain object和GUI object内的重复数据进行同步控制
两个classes都需要使用对方特性,但其间只有一条单向连接
添加一个反向指针,并使修改函数能够同时更新两条连接
两个classes之间有双向关联,但其中一个class如今不再需要另一个class的特性
去除不必要的关联
有一个字面数值,带有特别含义
创造一个常量,根据其意义为它命名,并将上述的字面数值替换为这个常量
Class中存在一个public值域
将它声明为private,并提供相应的访问函数
需要面对传统编程环境中的record structure
为该record创建一个哑数据对象(dumb data object)
Class之中有一个数值型别码,但它并不影响class的行为
以一个新的class替换该数值型别码
有一个不可变的type code,它会影响class的行为
以一个subclass取代这个type code
有一个type code,它会影响class的行为,但无法使用subclassing
以state object取代type code
各个subclasses的惟一差别只在返回常量数据的函数身上
修改这些函数,使它们返回superclass中的某个(新增)值域,然后销毁subclasses
有一个复杂的条件(if-then-else)语句
从if、then、else三个段落中分别提炼出独立函数
有一系列条件测试,都得到相同结果
将这些测试合并为一个条件式,并将这个条件式提炼成为一个独立函数
在条件式的每个分支上有着相同的一段代码
将这段重复代码搬移到条件式之外
在一系列布尔表达式中,某个变量带有控制标记(control flag)的作用
以break语句或return语句取代控制标记
函数中的条件使人难以看清正常的执行路径
使用卫语句(guard clauses)表现所有特殊情况
有个条件式,它根据对象类别的不同而选择不同的行为
将这个条件式的每个分支放进一个subclass内的覆写函数中,然后将原始函数声明为抽象函数
需要再三检查某物是否为null value
将null value替换为null object
某一段代码需要对程序状态做出某种假设
以assertion明确表现这种假设
函数的名称未能揭示函数的用途
修改函数名称
某个函数需要从调用端得到更多信息
为此函数添加一个对象函数,让该对象带函数所需信息
函数本体不再需要某个函数
将该函数去除
某个函数既返回对象状态值,又修改对象状态
建立两个不同的函数,其中一个负责查询,另一个负责修改
若干函数做了类似的工作,但在函数本体中却包含了不同的值
建立单一函数,以参数表达那些不同的值
有一个函数,其内完全取决于参数值而采取不同反应
针对该参数的每一个可能值,建立一个独立函数
从某个对象中取出若干值,将它们作为某一次函数调用时的参数
改使用(传递)整个对象
对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数也可以(也有能力)调用前一个函数
让参数接受者去除该项参数,并直接调用前一个函数
某些参数总是很自然地同时出现
以一个对象取代这些参数
Class中的某个域值,应该在对象初创时被设置,然后就不再改变
去掉该值域的所有设值函数
有一个函数,从来没有被其他任何class用到
将这个函数修改为private
希望在创建对象时不仅仅是对它做简单的建构动作
将constructor替换为factory method
某个函数返回的对象,需要由函数调用者执行向下转型动作
将向下转型动作移到函数中
某个函数返回一个特定的代码,用以表示某种错误情况
改用异常
面对一个调用者可预先加以检查的条件,抛出一个异常
修改调用者,使它在调用函数之前先做检查
两个subclasses拥有相同的值域
将此值域移至superclass
有些函数,在各个subclass中产生完全相同的结果
将该函数移至superclass
在各个subclass中拥有一些构造函数,它们的本体代码几乎完全一致
在superclass中新建一个构造函数,并在subclass构造函数中调用它
Superclass中的某个函数只与部分(而非全部)subclasses有关
将这个函数移到相关的那些subclasses去
Superclass中的某个值域只被部分(而非全部)subclasses用到
将这个值域移到需要它的那些subclasses去
Class中的某些特性只被某些(而非全部)实体用到
新建一个subclass,将上面所说的那一部分特性移到subclass中
两个classes有相似特性
为这两个classes建立一个superclass,将相同特性移至superclass
若干客户使用class接口中的同一子集;或者,两个classes的接口有部分相同
将相同的子集提炼到一个独立接口中
Superclass和subclass之间无太大区别
将它们合为一体
有一些subclasses,其中相应的某些函数以相同顺序执行类似的措施,但各措施实际上有所不同
将各个措施分别放进独立函数中,并保持它们都有相同的签名式(signature),于是原函数也就变得相同了。然后将原函数上移至superclass
某个subclass只使用superclass接口中的一部分,或是根本不需要继承而来的数据
在subclass中新建一个值域用以保存superclass;调整subclass函数,令它改而委托superclass;然后去掉两者之间的继承关系
在两个classes之间使用委托关系,并经常为整个接口编写许多极简单的请托函数
让请托(delegating)class继承受托class
某个继承体系同时承担两项责任
建立两个继承体系,并通过委托关系让其中一个可以调用另一个
有一些代码,以流程的过程化风格写就
将数据记录变成对象,将行为分开,并将行为移入相关对象之中
某些GUI class之中包含了domain logic(领域逻辑)
将domain logic分离出来,为它们建立独立的domain class
某个class做了太多工作,其中一部分工作以大量条件式完成
建立继承体系,以一个subclass表示一种特殊情况