您的位置:首页 > 编程语言

读书摘录之《重构-改善既有代码的设计》简要摘录

2013-08-15 10:11 225 查看
 

重构的原则

重构的定义:对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。也可以说:使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。

定义的扩展:第一,重构的目的是使软件更容易被理解和修改。第二,重构不会改变软件可观察的行为。

是用重构技术时,需要把时间分配给两种截然不同的行为:添加新功能,以及重构。添加新功能时,不应该修改既有代码,只管添加新功能。重构时不能再添加功能,只管改进程序结构。

 

重构的目的:

 改进软件设计

 使软件更容易理解

 帮助找到BUG

 提高编程速度

 

重构的时机

 三次法则

 添加功能时

 修补错误时

 复审代码时

 

重构的难题

 数据库

 修改接口

 难以通过重构手法完成的设计的改动

 何时不该重构

 

 

重构方案实施

重新组织函数

* Extract Method(提炼函数)

 函数过长,可以根据语义分解函数

 需要注释才能理解的代码放到独立函数中

* Inline Method(内联函数)

 针对某些函数,其内部代码和函数名称同样清晰易读,这样的函数应该去掉

 当手上有一群组织不合理的函数时,可以先将它们都内联到一个大型函数中,然后再提炼

* Inline Temp(内联临时变量)

 当某个临时变量被赋予了某个函数调用的返回值,可以直接去掉临时变量

* Replace Temp with Query(以查询取代临时变量)

 局部变量会使代码难以被提炼,应该尽可能把它们替换为查询式(用一个简单的查询函数替换)

*Introduce Explaining Variable(引入解释性变量)

 在条件逻辑中,表达式复杂难以阅读,可以使用临时变量帮助解释

 在较长的算法中,可以使用临时变量来解释每一步运算的意义

* Split Temporary Variable(分解临时变量)

 如果临时变量承担多个职责,就应该被替换为多个临时变量,每一临时变量只承担一个职责

* Remove Assignments to Parameters(移除对参数的赋值)

 不要对参数赋值,应该是临时变量替代.

* Replace Method with Method Object(以函数对象取代函数)

 如果一个函数中局部变量泛滥成灾,可以提炼函数对象,将所有局部变量都变成函数对象的字段.

* Substitute Algorithm(替换算法)

 如果一件事可以有更清晰的方式,就应该以较清晰的方式取代复杂的方式.

 

 

在对象之间搬移特性

 * Move Method 搬移函数

  如果一个类有太多行为

  一个类与另一个类有太多合作而形成的高度耦合

 * Move Field 搬移字段

  如果对于一个字段,在其所驻类之外的另一个类中有更多函数使用了它,那么就要搬移这个字段了

 * Extract Class 提炼类 :
建立一个新类,将相关的字段和函数从旧类搬移到新类

   当类含有大量函数和数据时,要考虑分离出去一部分.

 * Inline Class 将类内联化

   当类不再承担足够责任,不再有单独存在的理由时,可以考虑把类塞进另一个类中

 * Hide Delegate 隐藏“委托关系”

   如果某个客户先通过服务对象的字段得到另一个对象,然后调用后者的关系,这样就暴露了委托关系,我们可以在服务对象上放置一个简单的委托函数,将委托关系隐藏起来.

 * Remove Middle Man
移除中间人

  在委托调用中,随着受托类的特性的增加,服务类完全变成了一个"中间人",此时应该让客户直接调用受托类.

 * Introduce Foreign Method
引入外加函数

  如果你的类无法提供一项新的功能,你可以自行添加一个新函数

 * Introduce Local Extension
引入本地扩展

  当需要的外加函数比较多时,可以将这些函数组织起来,放到一个恰当的地方(子类化和包装可以实现)

 

重新组织数据

 * Self Encapsulate Field
自封装字段

   如果你想在访问超类中的一个字段,却又想在子类中对这个变量的访问改为一个计算后的值,此时可以使用此手法

 * Replace Data Value with Object
以对象取代数据值

   当用数据项表示简单情况时,当数据项的值开始产生不好的代码感观时,就可以使用对象代替了

 * Change Value to Reference
将值对象改为引用对象

   有时候,你会从一个简单的对象开始,在其中保存少量不可修改的数据.而后,你可能会希望给这个对象加入一些可修改的数据,并确保对任何一个对象的修改都能影响到所有引用此一对象的地方,这时就可以把这个对象变成一个引用对象了

 * Change Reference to Value
将引用对象改为值对象

   如果引用对象开始变得难以使用,也许就应该将它改为值对象

 * Replace Array with Object 
以对象取代数组

   当数组中容纳多种不同的对象时,请把数组改为对象

 * Duplicate Observed Data
复制“被监视数据”

   将用户界面和处理业务的逻辑代码分离时,数据往往需要内嵌到GUI控件中,因此需要保留两份,并保持同步

 * Change Unidirectional Association to Bidirectional
将单向关联改为双向关联

   开发初期,你可能会在两个类之间建立一条单向连接,是其中一个类可以引用另一个类。随着时间的推移,你可能发现被引用类需要得到其引用者以便进行某些处理,这个时候可以执行此法
 * Change Bidirectional Association to Unidirectional
将双向关联改为单向关联

   当双向关联不需要时,就应该去掉双向关联

 * Replace Magic Number with Symbolic Constant
以字面常量取代魔法数

   应该把Magic Number
替换为字面常量

 * Encapsulate Field
封装字段

   取消Public数据,以实现数据隐藏

 * Encapsulate Collection
封装集合

   取值函数不应该返回集合,设置函数也不应该直接设置集合

 * Replace Record with Data Class
以数据类取代记录

   当你面对一个遗留程序,后者需要通过传统API与记录结构交流,或者处理从数据库读取的记录,这时候,需要创建一个接口类,用以处理这些外来数据

 * Replace Type Code with Class
以类取代类型码

   以一个新的类取代数值型类型码

 * Replace Type Code with Subclasses
以子类取代类型码

   当类型码影响宿主类的行为时,可以借助多态来处理,使用子类取代类型码

 * Replace Type Code with State/Strategy
以State/Strategy 取代类型码

   你又一个类型码,它会影响类的行为,但是无法通过继承手法消除时,可以以状态对象处理类型码

 * Replace Subclass with Fields
以字段取代子类

   你的各个子类唯一的差别只是“返回常量数据”的函数,那么可以使用字段取代子类

 

简化条件表达式

 * Decompose Conditional
分解条件表达式

   当你有一个复杂的条件语句时,可以分别从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对象

 * Introduce Assertion
引入断言

   当某一段代码需要对程序状态做出某种假设,应该以断言明确表现这种假设

 

简化函数调用

 * 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 隐藏函数

  当函数从来没有被其他任何类用到,那么就要将这个函数修改为private

 * Replace Constructor with Factory Method
以工厂函数取代构造函数

  当你希望在创建对象时不仅仅是做简单的构建动作时,可以将构造函数替换为工厂函数

 * Encapsulate Downcast
封装向下转型

  某个函数返回的对象,需要由函数调用者执行向下转型,这个时候应该将向下转型的动作移到函数中

 * Replace Error Code with Exception
以异常取代错误码

  某个函数返回一个特定的代码,用以表示某种错误情况,应该改用异常

 * Replace Exception with Test
以测试取代异常

  面对一个调用者可以预先检查的条件,你却抛出了一个异常,可以修改调用者,使它在调用函数之前先做检查

 

处理概括关系

 * Pull Up Field 字段上移

  当两个字类拥有相同的字段时,将该字段移动至超类

 * Pull Up Method 函数上移

  有些函数,在各个子类中产生完全相同的结构,应该将该函数移至超类

 * Pull Up Constructor Body
构造函数本体上移

  各个子类中拥有一些构造函数,它们的本体几乎完全一致,那么可以把它们移动至超类

 * Push Down Method 函数下移

  超类中的某个函数只与部分子类有关,将这个函数移至相关的那些子类中去

 * Push Down Field 字段下移

  超类中的某个字段只被部分子类用到,将这个字段移动到需要它的那些子类中去

 * Extract Subclass 提炼子类

  类中的某些特性只被某些实例用到,可以新建一个字类,将那些特性移到子类中

 * Extract Superclass
提炼超类

  两个类有相似的特性,可以为这两个类建立一个超类,并将相同特性移至超类

 * Extract Interface
提炼接口

  若干客户使用类接口中的同一个子集,或者两个类的接口有部分相同,可以将相同的子集提炼到一个独立函数中

 * Collapse Hierarchy
折叠继承体系

  超类和子类之间无太大差别,可以将它们合为一体

 * From Template Method
塑造模板函数

  一些子类,其中相应的某些函数以相同顺序执行类似操作,但各个操作在细节上有所不同,这个时候,可以将这些操作分别放进独立函数,并保持它们有相同的签名,于是原函数也就变得相同了,然后将原函数上移至超类

 * Replace Inheritance with Delegation
以委托取代继承

  某个子类只使用超类接口中的一部分,或者根本不需要继承而来的数据,那么可以用委托取代继承

 * Replace Delegation with Inheritance
以继承取代委托

  如果两个类之间使用了委托关系,并经常为整个接口编写许多极简单的委托函数,那么让委托类继承接受委托类

 

大型重构

 Tease Apart Inheritance
梳理并分解继承体系

    建立两个继承体系,并通过委托关系让其中一个可以调用另一个

 Convert Procedural Design to Object
将过程化设计转化为对象设计

    将数据记录变成对象,将大块的行为分成小块,并将行为移入相关对象之中。

 Separate Domain from Presentation
将领域和表述/显示分离

    将领域逻辑分离出来,为它们建立独立的领域类

 Extract Hierarchy 提炼继承体系

    建立继承体系,以一个子类表示一种特殊情况

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: