refactor
文章
0 代码重构方法
代码重构的常用方法 (C++实现)0 概述重构定义重构是在软件开发中改善已有代码的一种方法,通过代码重构可以改进软件的设计、使得软件更容易理解、有利于Bug的发现以及提高后续开发效率。Martin Fowler在《重构:改善既有代码的设计》一书中对“重构”提供了两种形式的定义: 重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。 重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。 重构时机对于何时重构,Martin Fowler认为不能为重构而重构,应该在 “当你想做别的事情,而重构可以帮助你把那些事情做好” 时,才去进行重构。并给出了四个常见的重构时机: 事不过三,三则重构; 添加功能时重构; 修补错误时重构; 复审代码时重构。 对于何时不应该重构,Martin Fowler认为如果“既有代码是在太混乱,重构它还不如重新写一个简单”时就应该重写,而不是重构。重写的一个清晰的信号是:现有代码根本不能正常运作。 重构既是一件脑力活,也是一件体力活。特别是在软件中的“代码坏味道”积累...
1 坏的味道
1 代码坏味道1 Duplicated Code(重复代码)现象 同一个类的两个函数含有相同的表达式。 两个互为兄弟的子类内含相同的表达式(可能其中对应的某些函数以相同顺序执行类似的操作,但在各个操作的细节上有所不同)。 重构手法 Extract Method Extract Method->Pull Up Method (->Form Template Method) 2 Long Method(过长函数)现象 一个函数所承担的事情太多,导致代码行数过长(可能有临时变量存在)。 重构手法 Extract Method (->Replace Temp with Query) 3 Large Class(过大的类)现象 一个类做了太多的事情,不符合单一职责原则,导致代码过多。 重构手法 Extract Class 4 Long Parameter List(过长参数列)现象总体表现为一个函数的参数列表太长,可能伴随着以下两种现象: 向已有的对象发出一条请求就可以取代一个参数。 某些参数数据缺乏合理的对象归属。 重构手法 Replace Parame...
2 重新组织函数
2 重新组织函数1 Extract Method(提炼函数)概念Extract Method应该是最常用的重构手法了,当遇到一个过长的代码或者需要添加注释才能让人理解其用途的代码时,就可以运用Extract Method将代码提炼到一个函数上。该方法的一个重点时函数命名,只有给函数起个适当的名字时,他们才能真正起作用。对于是否使用该重构手法,代码长度不是问题,关键在于函数名称和函数本体之间的语义距离。 如果提炼可以强化代码的清晰度,那就去做,就算函数名称比提炼出来的代码还长也无所谓。 重构实例1123456789// 重构前void PrintOwing(double amount){ PrintBanner(); // print details cout << "name: " << m_name << endl; cout << "amount: " << amount << endl;} 123456789101112...
3 在对象之间搬移特性
3 在对象之间搬移特性1 Move Method(搬移函数)如果某个函数使用另一个对象的次数比使用自己所驻对像的次数多,就可以使用Move Method将函数搬移到另一个对象。当函数中用到了原来对象的属性时,搬移后可以把原来对象this作为入参。 重构示例7123456789101112131415161718192021222324252627// 重构前class Account {public: double OverdraftCharge() { if (m_type->IsPremium()) { double result = 10; if (m_dayOverdrawn > 7) { result += (m_dayOverdrawn - 7) * 0.85; } return result; } return m_d...
4 重新组织数据
4 重新组织数据1 Self Encapsulate Field(自封装字段)直接访问一个字段,后面如果与该字段的耦合关系逐渐变得笨拙时,可以使用Self Encapsulate Field手法进行重构,为这个字段建立取值/设值函数,并且只以这些函数来访问字段。 重构示例101234567891011// 重构前class Range {public: bool Includes(int arg) { return arg >= m_low && arg <= m_high; }private: int m_low; int m_high;} 1234567891011121314151617181920// 重构后class Range {public: bool Includes(int arg) { return arg >= GetLow() && arg <= GetHig...
5 简化条件表达式
5 简化条件表达式1 Decompose Conditional(分解条件表达式)复杂的条件逻辑会降低代码的可读性,通过从if/else if/else三个段落中分别提炼出独立的函数,根据每一段落的用途命名函数,从而更清晰地表达自己的意图。 重构示例13123456// 重构前if (date.Before(SUMMER_START) || date.After(SUMMER_END)) { charge = quantity * m_winterRate + m_winterServiceCharge;} else { charge = quantity * m_summerRate;} 123456789101112131415161718192021// 重构后if (NotSummer(date)) { charge = WinterCharge(quantity);} else { charge = SummerCharge(quantity);}...
6 简化函数调用
6 简化函数调用1 Introduce Parameter Object(引入参数对象)在代码中,可能有一组参数总是一起被传递到好几个函数中,这样的一组参数就是所谓的Data Clumps(数据泥团)。最常见的就是指代一个时间范围的startTime/endTime。可以通过Introduce Parameter Object手法,以一个对象取代这些参数。 重构示例19123456789101112131415// 重构前class Account {public: double GetFlowBetween(Date& startTime, Date& endTime) { double result = 0.0; for (auto& entry : m_entries) { if (entry.GetDate() == startTime || entry.GetDate() == endTime || (entry.G...
7 处理继承关系
7 处理继承关系1 Pull Up Field(字段上移)如果两个子类有相同的字段,则将该字段上移至超类中。 2 Pull Up Method(函数上移)如果两个子类有相同的函数而且产生完全相同的结果,则将该函数上移至超类。 3 Extract Superclass(提炼超类)如果两个类有相似特性,可以为这两个类建立一个超类,将相同特性移至超类。如果继承不合适,可以使用[Extract Class](#Extract Class)来提取重复代码。 4 Form Template Method(塑造模板函数)该重构的手法其实就是设计模式中的模板模式,如果有一些子类,其中对应的某些函数以相同顺序执行类似的操作,但在各个操作的细节上有所不同。可以将这些操作分别放到独立的函数中,替换在原函数中原有的操作代码,并上移至超类。 重构示例2212345678910111213141516171819202122232425262728// 重构前class Site {public: virtual double GetBillableAmount() = 0; /...
附录1 代码重构理论
重构 参考文献 https://www.cnblogs.com/ranjiewen/p/5912259.html https://blog.csdn.net/ruanrunxue/article/details/102945431 1 什么是重构?重构的定义Martin Fowler在《重构:改善既有代码的设计》一书中给出了重构的两个定义. 第一个是名词形式:Refactoring: 对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本. 第二个是动词形式:Refactor: 使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构. 重构的目标重构的目标是什么? 重构的目标绝不是将代码从别人的taste改成自己的taste,也不是将代码从一种坏味道改到另一种坏味道!Matin Fowler利用上面两个定义,指出了重构的目标: 不改变软件可观察行为 提高软件可理解性 降低软件修改成本 而对于上述目标,我们再深入一点分析,发现其实已经有更经典的定义. 那就是Kent Beck的简单设计四原则: Pass All Tes...














