复用与现实
问题
- 程序员不知道如何重构
- 如果重构利益是长远的,何必现在付出?收益时,已经不在职位上了。
- 代码重构是一项额外工作,老板付钱时开发新功能
- 重构可能破坏现有程序
思路
先行者和早期接受者感兴趣的是新技术、“范式移转和突破性的思想的愿景”。
早期和晚期消费群体则主要关心成熟度、成本、支持,以及这种新思想或新产品是否被与他们有着相似需求的其他人成功套用。
要打动并说服软件开发者和软件研究者是完全不同的。
必须主管人员精心制定策略,在中阶经理层组织领导会议、项目开发组协商,通过研讨会和出版物向广大研究人员和开发人员宣扬这些技术的好处。比较重要的几件事:对员工进行培训、尽量获取短期利益、减少开销、安全引入新技术。
重构工具
总结
何时该使用、何时不该使用、何时开始、何时通知,这种节奏
如何学习
- 随时挑一个目标
- 没把握就停下来
- 学习原路返回
- 结队
一点点慢慢解决,添加新功能,添加测试,记录清单需要重构的、需要文档的、需要划的图
要点列表
如果你发现自己需要为程序添加一个特性,而代码结构使你无法很方便地达成目的,那就先重构那个程序,使特性的添加比较容易进行,然后添加特性。
重构前,先检查自己是否有一套可靠的测试机制。这些测试必须有自我检验能力。
重构技术就是以微小的步伐修改程序。如果你犯下错误,很容易便可发现它。
任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员。
重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性、降低其修改成本。
事不过三,三则重构。
不要过早发布接口。请修改你的代码所有权政策,使重构更顺畅。
当你感觉需要撰写注释时,请先尝试重构,试着让所有注释都变得多余。
确保所有测试都完全自动化,让它们检查自己的测试结果。
一套测试就是一个强大的bug侦测器,能够大大所见查找bug所需要的时间。
频繁地进行测试。每次编译请把测试页考虑进去 每天至少执行每个测试一次。
每当你收到bug报告,请先写一个单元测试来暴露这只bug
编写不完善的测试并实际进行,好过对完美测试的无尽等待。
考虑可能出错的边界条件,把测试火力集中在那儿。
当事情被大家认为应该会出错时,别忘了检查是否抛出了预期的异常。
不要因为测试无法捕捉所有bug就不写测试,因为测试的确可以捕捉到大多数bug。
说明
《重构-改善既有代码的设计》Martin Fowler 摘要: 第十三章 复用与现实、 第十四章 重构工具、 第十五章 总结、 后续:要点
你也可以访问:http://txidol.github.io 获取更多的信息
特点
根据需要安排自己的工作,只在需要添加新功能或修补错误时才进行重构。
进行大规模重构时,有必要为整个开发团队建立共识。意识到:重构正在进行,每个人都应该相应地安排自己的行动。
Tease Apart Inheritance 梳理并分解继承体系
某个继承体系同时承担两项责任
建立两个继承体系,并通过委托关系让其中一个可以调用另一个。
如果继承体系中的某一特定层级上的所有类,其子类名称都以相同的形容词开始,那么这个体系很可能就承担着两项不同的责任。
ConvertProcedural Design to Objects 将过程化设计转化为对象设计
手上有些传统过程化风格的代码
将数据记录变成对象,将大块的行为分成小块,并将行为移入相关对象之中。
Separate Domain from Presentation 将领域和表述/显示分离
某些GUI类之中包含了领域逻辑
将领域逻辑分离出来,为它们建立独立的领域类。
Extract Hierarchy 提炼继承体系
你有某个类做了太多工作,其中一部分工作是以大量条件表达式完成
建立继承体系,以一个子类表示一种特殊情况。
以上重构都包含前面章节提到的一系列或一组重构手法。
说明
《重构-改善既有代码的设计》Martin Fowler 摘要: 第十二章 大型重构
你也可以访问:http://txidol.github.io 获取更多的信息
有一批重构手法专门处理类的概括关系(generalization , 即继承关系)
Pull Up Field 字段上移
两个子类有相同字段 --》 移到超类
观察函数如何使用它们,使用的方式很相似,考虑归纳到超类
Pull Up Method 函数上移
有些函数,在各个子类中产生完全相同的结果。
将该函数移至超类
某些用到了子类中的参数,可以在父类做一个取值的抽象方法
Pull Up Constructor Body 构造函数本体上移
你在各个子类中拥有一些构造函数,它们本体几乎完全移至。
在超类中新建一个构造函数,并在子类构造函数中调用它
Push Down Method 函数下移
超类中的某个函数只与部分子类有关
Push Down Field 字段下移
Extract Subclass 提炼子类
类中的某些特性只被某些实例用到。
新建一个子类,将上面所说的那部分特性移到子类中
Extract Superclass 提炼超类
两个类有相似特性
为这两个类建议一个超类,将相同特性移至超类
Extract Interface 提炼接口
若干客户使用类接口中的同一子集,或者两个类的接口有部分相同
将相同的子集提炼到一个独立接口中
Collapse Hiberarch 折叠继承体系
超类和子类之间无太大区别 将它们合为一体
Form TemPlate Method 塑造模板函数
你有一些子类,其中相应的某些函数以相同顺序执行类似的操作,但各个操作的细节上有所不同。
将这些操作分别放进独立函数中,并保持它们都有相同的签名,于是原函数也就变得相同了,然后将原函数上移至超类。
Replace Inheritance with Delegation 以委托取代继承
某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据。
在子类中新建一个字段用以保存超类;调整子类函数令它改为委托超类;去掉继承关系。
Replace Delegation with Inheritance 以继承取代委托
两个类使用委托关系,且许多极简单的委托函数。
注意:所托对象不止一个其他对象共享,且受托对象是可变的。不能变为继承关系。
说明
《重构-改善既有代码的设计》Martin Fowler 摘要: 第十一章 处理概括关系
你也可以访问:http://txidol.github.io 获取更多的信息
Rename Method 函数改名
改一个自表达的名字吧!骚年
Add Parameter 添加参数
某个函数需要从调用端得到更多信息。
为此函数添加一个对象参数,让该对象代价函数所需信息。并发编程大多数参数很长,不放在一个类中,因为这样你可以保证传递给函数的参数都是不可修改的。
Remove Parameter 移除参数
移除不必要的某个参数
Separate Query from Modifier 将查询函数和修改函数分类
某个函数既返回对象状态值,又修改对象状态
建立两个函数,一个查,一个改。多线程一般查改一起,那么提供第三个方法调另两个。
Parameterize Method 令函数带参数
若干函数做了类似的工作,但在函数本体中包含了不同的值
建立单一函数,以参数表达那些不同的值
以“可将少量数值视为参数”为依据,找出带有重复性的代码。提炼参数
Replace Parameter with Explicit Methods 以明确函数取代参数
你有一个函数,其中完全取决于参数值而采取不同行为
针对该参数的每一个可能只,建立一个独立函数。
Preserve Whole Object 保持对象完整
你从某个对象去除若干值,将它们作为某一次函数调用时的参数
改为传递整个对象
Replace Parameter with Methods 以函数取代参数
对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数本身也能够调用前一个函数。
让参数接受者去除该项参数,并直接调用前一个函数。
Introduce Parameter Object 引入参数对象
某些参数总是很自然地同时出现。
以一个对象取代这些参数。
还可以适当的行为从其他函数移到这个新建对象中。
Remove Setting Method 移除设置函数
类中某个字段应该在对象创建时被设置,然后就不再改变。
Hide Method 隐藏函数
没有被其他任何类用到
Replace Constructor with Factory Method 以工厂函数取代构造函数
希望创建对象时不仅仅是做简单的构建动作
Encapsulate Downcast 封装向下转型
某个函数返回的对象,需要由函数调用者执行向下转型
将向下转型动作移到函数中
Replace Error Code with Exception 以异常取代错误码
Replace Exception with Test 以测试取代异常
面对一个调用者可以预先检查的条件,你抛出了一个异常
修改调用者,使它在调用函数之前先做检查
说明
《重构-改善既有代码的设计》Martin Fowler 摘要: 第十章 简化函数调用
你也可以访问:http://txidol.github.io 获取更多的信息
Decompose Conditinal 分解条件表达式
你有一个复杂的条件(if-then-else)语句
从三个段落中分别提炼出独立函数
Consolidate Conditional Expression 合并条件表达式
你有一系列条件测试,都得到相同结果
将这些测试合并成为一个条件表达式,并将这个条件表达式提炼成为一个独立函数
检查用意更清晰,有时也不用这么做
Consolidate Duplicate Conditional Fragments 合并重复的条件片段
在条件表达式的每个分支上有着相同的一段代码
将这段重复代码搬移到条件表达式之外
Remove Control Flag 移除控制标记
在一系列布尔表达式中,某个变量带有“控制标记”作用
以break语句或return语句取代控制标记
Replace Nested Conditional with Guard Clauses 以卫语句取代嵌套条件表达式
函数中的条件逻辑使人难以看清正常的执行路径
使用卫语句(单独检查)表现所有特殊情况
Replace Conditional with Polymorphism 以多态取代条件表达式
你手上有个表达式,它根据对象类型的不同而选择不同的行为。
将这个条件表达式的每个分支放进一个子类内的覆写函数中,将原始函数声明为抽象函数。
Introduce Null Object 引入Null对象
你需要再三检查某对象是否为null
将null值替换为null对象
空对象一定是常量,它们的任何成分都不会发生变化。
Nullabel接口 Null接口 同样的方法
常常可以看到空对象会返回其他空对象 。
Null Object 模式 Special Case模式 特例类 NAN 降低“错误处理”开销
Introduce Assertion 引入断言
某一段代码需要对程序状态做出某种加上
以断言明确表现这种假设
检查一定必须为真的条件
说明
《重构-改善既有代码的设计》Martin Fowler 摘要: 第九章 简化条件表达式
你也可以访问:http://txidol.github.io 获取更多的信息
Self Encapsulate Field 自封装字段
你直接访问一个字段,但与字段之间的耦合关系逐渐变得笨拙。
为这个字段建立取值/设置函数,并且只以这些函数来访问字段。
子类用超类数据时
Replace Data Value with Object 以对象取代数据值
你有一个数据项,需要与其他数据和行为一起使用才有意义
值对象应该是不可修改内容的
Change Value to Reference 将值对象改为引用对象
你从一个类衍生出许多彼此相等的实例,希望将它们替换为同一个对象
Change Reference to Value 将引用对象改为值对象
你有一个引用对象,很小且不可变,而且不易管理
Replace Array with Object 以对象取代数组
你有一个数组,其中的元素各自代表不同的东西
Duplicate Observed Data 复制“被监视数据”
你有一些领域数据置身与GUI控件中,而领域函数需要访问这些数据。
将该数据复制到一个领域对象中。建立一个Observer模式,用以同步领域对象和GUI对象内的重复数据。
Change Unidirectional Association to Bidirectional 将单向关联改为双向关联
两个类都需要使用对方特性,但其间只有一条单向连接
单向可以将所有关联关系的逻辑集中安置于一地。
Change Bidirectional Association to Unidirectional 将双向关联改为单向关联
两个类之间有双向关联,但其中一个类如今不再需要另一个类的特性。
双向关联的弊病: 维护复杂的创建 删除 以及僵尸对象 高耦合
Replace Magic Number with Symbolic Constant 以字面常量取代魔法数
你有一个字面数值,带有特别含义
创建一个常量,根据其意义为它命名,并将上述的字面数值替换为这个常量。
Encapsulate Field 封装字段
Encapsulate Collection 封装集合
有一个函数返回一个集合
让这个函数返回该集合的一个只读副本,并在这个类中提供添加/移除集合元素的函数。
Replace Record with Data Class 以数据类取代记录
你需要面对传统编程环境中的记录结构
为该记录创建一个“哑”数据对象
Replace Type Code with Class 以类取代类型码
类之中有一个数值类型码,但它并不影响类的行为
以一个新的类替换该数值类型码
Replace Type Code with SubClasses 以子类取代类型码
你有一个不可变的类型码,它会影响类的行为。
Replace Type Code with State/Strategy 以策略模式取代类型码
类型码影响类行为,且无法通过继承手法消除它。
以状态对象取代类型码
Replace SubClass with Fields 以字段取代子类
各个子类的唯一差别只在“返回常量数据”的函数身上。
修改这些函数,使他们返回超类中的某个(新增)字段
说明
《重构-改善既有代码的设计》Martin Fowler 摘要: 第八章 重新组织数据
你也可以访问:http://txidol.github.io 获取更多的信息