《重构--改善既有代码的设计》 --MartinFowler


《重构--改善既有代码的设计》 --Martin Fowler

重构定义: 在不改变软件可观察行为的前提下,对软件内部进行调整(使用重构手法),以提高其可理解性,降低其修改成本。 -- 重点在两点: 1. 不改变软件的可观察行为。2. 提高其可理解性。

两个目的:1. 添加新功能。 2. 重构。  --重构就只管修改程序结构,不要添加新功能。 添加新功能就不要修改既有代码。两者混合进行会使得程序朝不可理解的方向发展。

ps: 重构与设计模式具有辩证的关联性,模式是目的,重构是到达之路。重构促进设计模式的形成与稳定,模式为重构提供前进方向,二者相辅相成,具有统一性。


为什么需要重构: 
1. 面对迅速变化的需求,对原有的代码进行修改十分困难(逻辑复杂,条理不清晰,很难兼顾;改动接口多,测试困难), 尤其对于某些无法限定影响面的接口修改。
2. 使得原有设计保持本真意义。代码结构的流失具有累积性,原有的设计及意图难以保持,阅读源代码很难理解原来的设计。
3. 消除重复代码,重复代码越多,修改的风险越大,修改带来的不一致性可能越大(修改一处,未修改另一处)
4. 使得软件更容易理解,结构更清晰,代码更简洁。
5. 帮助找到bug
6. 提高编程速度    -- 维持良好设计,清晰的意图,从而使得编程更加容易。
7. 重构与新功能    -- 如果你发现自己需要添加一个特性,而代码结构使你无法很方便地达成目的,那就先重构那个程序,使特性比较容易进行,然后再添加特性。
8. 重构与性能        -- 重构调整代码结构,使性能调优更加方便的进行。

何时重构:
1. 三次法则            --代码忍受了3次,就不要再忍受了,重构吧!
2. 添加新特性时候重构    -- 新特性的添加需要修改原先代码,且修改方案复杂
3. 复审代码时重构        -- 代码评审 谈谈如何重构
4. 重复代码过多
5. 函数过长            -- 一个函数应该只包含一个独立的逻辑功能。 这样将逻辑单元打散,可以减少代码耦合,并且更加清晰。
6. 过大的类            -- 一个类中出现太多实例变量,容易出现重复混乱的代码,可以考虑重构出子类。
7. 参数列表过长

坏代码的味道(什么样的形式才是坏代码):
重复代码
过长函数
过大的类
发散式变化: -- 一个类收到多个因素的影响,将朝着多个不同的方向变化,可以将类拆解成多个不同的类,然后桥接起来。
散弹式变化: -- 一个类的变动会印象多个其他的类,则可以将受此类影响的代码都放入这个类中。
同步式变化: -- 两个东西总是一起变化,如引用与数据,则将这两个同时变化的东西放入同一个类中。
数据泥团:   -- 一些零散的数据项出现在许多不同的类,或者函数的参数列表中。则可以将这些相同数据项抽取到一个类中。
基本类型偏执 -- 对于可以运用对象来表述一个物体,不用基本类型。如日期,时间等
多态扩展:   -- 替换switch case 根据类型多态扩展。
平行继承体系  -- 如果为一个类增加子类,必须为另一个类增加子类。可让一个体系引用另一个体系实例
冗赘类        -- 一个类没有多大的实际意义,没必要让人花时间、精力来了解
夸夸奇谈的未来性 -- 某些代码没有多大作用,只是觉得未来可能有用,从而使得系统更难维护和理解
令人迷惑的暂时字段 -- 某些字段只在特殊情况下才被使用到,让人不知其设置目的
过长的调用链路 -- 客户端需要很长的调用链来获取一个值,可以通过委托来获取最终值
中间人        -- 存在过多不必要的委托
狎昵关系        -- 类之间的调用关系较多,依赖较强。可以将一些方法或字段,移动到需要的类中。
异曲同工的类    -- 两个函数做同一件事情,却有着不同的签名。可以根据用途来命名,并抽离重复代码。
不完美的类库     -- 类库缺少需要的功能
纯稚的数据类     -- 未对数据进行封装,数据接口暴露
被拒绝的遗赠    -- 子类完全未使用父类的代码
过多的注释    -- 让代码自身具有注释功能

重构难题:
1. 数据库改动        -- 可以增加数据库接入层,使得数据库的变化和业务的变化分离
2. 接口改动        -- 对于已经发布的接口,并被不可控系统使用的时候,则不能重构接口
3. 设计的改动        -- 对系统已有的设计进行重构,不如重新设计并实现。
4. 项目十分紧张    -- 对于业务十分紧张的项目,不应该重构。

如何重构:
-- 如何面对不断变化的世界,如何面对不断变化的需求。 只有深层次的抽象出不变的对象,然后将变化东西放在叶子类中,与其维护的数据结构同在, 通过继承与多态来应对这种变化。

1. 可靠的测试环境。 --构建自动化单元测试套件(首推TestNG,尽量做到逻辑、边界全覆盖, 预期抛出的异常也要测试),并有独立的团队进行功能(黑盒)测试,测试出现bug再通过单元测试定位bug。ps:在写单测的过程中可以适当关注下代码运行性能。
2. 以微小的步伐修改程序。犯错可以很容易发现,配合可靠的测试。 重构节奏: 小修改,测试;小修改,测试;小修改,测试........   -- 重构十分强调微小的修改步伐, 便于测试和审查,以减少引发bug的风险
3. 在重构函数内部修改变量名称,清晰贴切。
4. 函数应该与它所使用的数据结构在同一对象内。
5. 查找引用    -- 通过文本工具查找你需要修改地方的引用,同时利用编译器发现错误。对于被反射引用的地方,一定要记录并进行详细的测试。

重构手法:
一、重新组织函数
1. 提炼函数    Extract Method
    * 概述:将一段代码放入一个独立函数中,并让函数名称解释该函数的用途。
    * 动机:厌恶过长的代码。如果函数过长,则很难被理解(用途不清晰,需要大段的注释描述意图),测试也困难;相反,如果一个函数够小、有清晰意图的命名,则被复用的机会更大,函数也更容易被修改。
    * 做法:编写一个新函数,根据这个函数的意图来命名  -- 如果能对一段代码给予一个更好表达其意图的命名,都可以提炼她。
    * 注意:这个重构手法最困难的地方在于提炼局部变量:
            1. 如果需要读取源函数的局部变量,则可将其作为参数传入新函数。
            2. 如果某些局部变量需要在目标函数后面使用,可能需要新函数返回该局部变量改变的值。
            3. 对于需要修改多个局部变量的情况,则可不提炼此段代码,或者将所有临时变量抽取为一个类。

扫描二维码关注公众号,回复: 4360353 查看本文章

2. 内联函数    Inline Method
    * 概述:在函数调用点插入函数本体,然后移除该函数
    * 动机:1.有些函数的内部代码比函数名本身更加清晰易读,则可以内联。2.函数调用混乱,可以先全部内联在一起,然后重新提炼。
    * 做法:检查多态覆盖,检查函数引用,引用点直接替换为函数。

3. 内联临时变量    Inline Temp
    * 概述:将所有对该变量的引用动作,替换为对她赋值表达式。
    * 动机:临时变量可能妨碍其他的内联手法。
    * 做法:确保只被一个简单的表达式赋值了一次

4. 以查询取代临时变量    Replace Temp with Query
    * 概述:程序以某个临时变量保存表达式的运算结果。则将一个表达式提炼到一个函数中,将将对这个临时变量的引用替换为对新函数的调用
    * 动机:临时变量总是驱使你写更长的函数,因为临时变量只在函数内可以访问到,所以将一些运算得到的临时变量提炼为一个函数,可以在任何时候访问。ps: 导致重复计算,但是使代码清晰。
    * 做法:确保该临时变量只被赋值一次,然后用新函数替换引用处。可以先将该临时变量声明为final,让编译器保证只赋值一次。

ps: 1,2,3,4的操作都让代码结构变得更加清晰、简洁,使得函数名称本身便具有自注释功能。

5. 引入解释性变量    Introduce Explaining Variable
    * 概述:将复杂表达式(或其中一部分)的结果放入一个临时变量,以这个变量的名称来解释表达式用于
    * 动机:将一个复杂的表达式进行拆解,用临时变量的名称来表达部分过程的意图。

6. 分解临时变量    Split Temporary Variable
    * 概述:程序中某个临时变量有多个用途,既不是循环变量,也不是收集计算结果变量,则应该对每个用途编写一个临时变量
    * 动机:临时变量有不同的用途,或者由不同含义的操作计算而得到,则不应该使用同一临时变量。

ps: 5,6的拆解都是为了使得表达式的意图更加清晰,各种复用临时变量,复杂计算过程等代码都可能让代码变得含混。

7. 移除对参数的赋值    Remove Assignments to Parameters
    * 概述:代码对一个参数进行赋值,应该用一个临时变量取代参数的位置。
    * 动机:对参数的赋值可能改变其引用的对象(引用参数), 从而丢失了原来的入参引用。所以将参数赋值给一个临时变量以改变这种含混性。

8. 以函数对象取代函数    Replace Method with Method Object
    * 概述: 有一个大型函数,其中过多的局部变量无法进行函数提炼,则将这个放入一个单独对象中,这样局部变量就成了对象的成员变量,然后在对象内将大型函数分解为多个小函数
    * 动机: 局部变量太复杂,根本无法拆解, 则使用一个对象来描述该方法。    -- 该对象需要有一个与方法意图对应的命名。
    * 做法:    1. 建立一个新类,并将原类作为该类的一个常量引用
            2. 新类中提供构造函数接收原对象,及原函数的所有参数。
            3. 在新类中提供一个函数,将原函数的代码复制到其中,通过原对象引用相应变量。

9. 替换算法    Substitute Algorithm
    * 概述:将函数本体替换为另一个算法
    * 动机:原函数的算法实现比较复杂,切不清晰,或者性能不好。如果你发现有更好的实现方式,勇敢的壮士断腕,替换该算法吧。


二、在对象间搬移特性
1. 搬移函数    Move Method
    * 概述:将一个函数移动到另一个类中去
    * 动机:类中一个函数与其他的类进行频繁的交流,而与本类交流较少,则将函数移到另一个类中,从而减少调用关系。
    * 做法:搬移一个或者一组相关的函数;检查源类的子类和超类是否有该函数的其他声明(覆盖,委托等问题);修改源函数使之成为一个委托函数。

2. 搬移字段    Move Field
    * 概述:将类中一个字段搬移到其他类中
    * 动机:本类中的一个字段,被其他类中的字段使用次数更多,搬移字段减少调用关系,间接提高信息隐藏性。
    * 做法:如果字段被很多地方引用,则先使用自我封装(Self-Encapsulation)将字段变成设/取值函数,然后搬移字段,最后修改设/取值函数为一个委托。

3. 提炼类    Extract Class
    * 概述:建立一个新的类,将相关的字段和函数从旧类中搬移到新类
    * 动机:1. 一个类的方法过多、责任过大做了由两个类做的事情。主要是由于当前类对于场景的抽象不够细致,导致过于复杂。
           2. 一个类中的数个特性朝着不同方向发展,从而变得无所关联。最主要的表现是子类化,某些特性需以一种方式子类化,某些特性以另一种方式子类化    
    * 做法:从一个类中搬移函数和字段到一个新类中,使得新类作为一个事物的更细致抽象。
    * 例如:一个person类有地址字段和函数,比较复杂。可以将地址抽象为一个新类,然后person调用这个地址类。

4. 内联类    Inline Class
    * 概述: 将一个类的所有特性搬移到另一个类中,然后移除该类
    * 动机: 这个类没有做太多事情
    * 做法: 上述的反过程

5. 隐藏委托关系    Hide Delegate
    * 概述: 在服务类建立客户所需的所有函数,用以隐藏委托关系
    * 动机: 对内部进行封装,通过一个委托类来调用其他对象,这样调用者可以不用了解内部变化,从而降低修改风险。
    * 做法: 正如设计模式中的代理模式等, 不仅隐藏调用关系,还可以对调用进行统计等管理。

6. 移除中间人    Remove Middle Man
    * 概述: 直接调用受托类
    * 动机: 某个类做了过多的简单委托,每添加一个新特性都需要在委托类中进行相应添加。
    * 做法: 上述反过程

7. 引入外加函数    Introduce Foreign Method
    * 概述: 在客户类中建立一个函数,并以第一参数形式传入一个服务类实例
    * 动机: 由于代码修改权不在自己手里,但是需要为某个类添加新特性。可以在外层写这样一个函数,并所需要的值都以参数传入。
    * 做法: 在拥有代码所有权后,将此函数返回她该去的地方

8. 引入本地扩展    Introduce Local Extension
    * 概述: 当需要为一个服务类提供一些额外的函数,但是你无法修改。可建立一个新类,使她包含这些额外的函数。让这个扩展类成为源类的子类或者包装类
    * 动机: 为类做扩展,可以使用装饰模式或者继承,使用继承请确保必定有继承关系。

ps: 从以上重构方法可以看出,其最终都是为了减少了代码中的调用关系,提高代码的意图表达。

三、 重新组织数据
1. 自封装字段    &封装字段    &封装集合        Self Encapsulate Field & Encapsulate Field & Encapsulate Collection
    * 概述:将字段进行封装,然后提供设/取值函数,对于集合取值只能返回可读的副本
    * 动机:隐藏内部数据接口,这样就算字段数据结构发生变化,只需要调整设/取值函数,从而不影响其他类的调用; 对于集合需要防止外部对引用的修改; 方便上syncrized关键字

2. 以对象取代数据值    Replace Data Value with Object
    * 概述:将数据项变为字段
    * 动机:数据项为对一个事物属性的描述,你无法估量这个场景下该事物属性的复杂性,所以用一个类构建该数据项,能够抗击未来的变化。

3. 将值对象改为引用对象    Change Value to Reference
    * 概述:将这个值对象变成引用对象
    * 动机:对一个对象修改的数据,能够影响引用这个对象的地方

4. 将对象引用改为值对象    Change Reference to Value
    * 概述:将引用对象变为一个值对象
    * 动机:利用其不可变性质

5. 用对象取代数组    Replace Array with Object
    * 概述:以对象替换数组,对于数组中的每个元素,以一个字段来表示
    * 动机:有些其他语言,将一个对象的属性存放在一个数组中了。将其重构为对象,从而可用字段名逐一描述

6. 复制被监视数据    Duplicate Observed Data
    * 概述:将数据复制到一个领域对象中,建立一个observer模式,用于同步领域对象和GUI对象内的数据
    * 动机:分离界面显示和业务逻辑,在界面更新数据的时候同步更新领域对象数据

7. 将单向关联改为双向关联    Change Unidirectional Association to Bidirectional
    * 概述:添加一个反向指针,并使修改函数能够同时更新两条连接
    * 动机:使得两个类相互依赖,方便访问对方的成员。 虽然方便,但是调用关系复杂,容易产生僵尸对象,修改时相互影响。

8. 将双向关联改为单项关联    Change Bidirectional Association to Unidirectional
    * 概述:去掉不必要的关联
    * 动机:降低类间复杂度

9. 以字面常量取代魔法数    Replace Magic Number with Symbolic Constant
    * 概述:创造一个常量,根据其意义命名,并将有特殊意义的字面数值替换为这个常量
    * 动机:魔数-有特殊意义的数字,使用一个常量来表示这个数字的意义

10. 以数据类取代记录    Replace Record with Data Class
    * 概述:面对传统编程的记录结构,为该记录创建一个'哑'数据对象
    * 动机:与数据库的记录进行交互,ORM

11. 以类取代类型码    Replace Type Code with Class
    * 概述:用一个新的类替换该类中用常量数值表示的类型
    * 动机:其实就是使用枚举类型来代替常量枚举,这样使得类型被更有意义的描述,并且提供了对应的操作函数,对于复杂的类型十分方便。

12. 以子类取代类型码    Replace Type Code with Subclasses
    * 概述:为类型码建立一个继承宿主类的子类,将根据这个类型码执行的操作,放入到一个子类中去。
    * 动机:将不同类型码的操作都放入对应的子类中,这样不经让代码更清晰,同时防止错乱。

13. 用状态或者策略取代类型码    Replace Type Code with State/Strategy
    * 概述: 类中有类型码会影响类的行为,但是无法通过继承手法来消除
    * 动机: 无法直接继承宿主类,则自己定义一个抽象的类去继承,与上述一致。

14. 以字段取代子类    Replace Subclass with Fields
    * 概述: 各个子类的差别不是打,只在一些常量数据上
    * 动机: 将子类中的共同行为搬移到超类,并在超类中定义这组差异的常量。减少无必要的编码

四、 简化条件表达式
1. 分解条件表达式        Decompose Conditional
    * 概述:有一个复杂的条件表达式,从if then else中分别提炼出独立函数
    * 动机:复杂的条件逻辑常常导致代码复杂度的提高,提炼不同分支,并按照意图命名,是代码可读性和清晰提高

2. 合并条件表达式        Consolidate Conditional Expression
    * 概述:有一些列的条件测试,但是都返回相同结果,则合并这些表达式
    * 动机:有一些表达式虽然条件不同,但是结果一样,将这些条件合并

3. 合并重复的条件片段    Consolidate Duplicate Conditional Fragment
    * 概述:条件表达式的每个分支有相同的一段代码,将这些代码抽取出来,放入表达式之外
    * 动机:将每个分支都执行的代码,搬移到代码执行分支之外,简化分支表达式,以使代码更加清晰。

4. 以卫语句取代嵌套条件表达式    Replace Nested Conditional with Guard Clauses
    * 概述:用卫语句处理特殊情况,卫语句就是if then return这种形式的表达式,常用于函数入口处,保护函数体只接受正确的参数。
    * 动机:对于情况比较特使的逻辑,使用此表达式可以简化代码,使之更加清晰

5. 以多态取代条件表达式    Replace Conditional with Polymorphism
    * 概述:将条件表达式的分支,放入每个子类的覆写函数中,并将原始函数声明为abstract
    * 动机:子类覆盖超类的条件表达式,在子类中只关注与自己相关的条件和行为。这样将集中在一起的逻辑打散到各个子类中。

6. 引入Null对象        Introduce Null Object
    * 概述:当需要再三检查对象是否为null,则将null值替换为一个null对象
    * 动机:为原类建立一个子类,其行为就是原类的null版本,可以方便多态的进行。空对象的存在,可以省去判空逻辑(判空逻辑只写在Null对象内部,其他写在超类)。

7. 引入断言            Introduece Assertion
    * 概述:某段代码需要对程序状态做出某种假设,以断言明确表现这种假设
    * 动机:断言可以帮助阅读程序代码所做的假设,可以在调试和调试,测试中广泛使用

ps: 这些方法都为了减少条件表达式的复杂性,提高其清晰度和意图,使用多态和空对象的方式,在一定程度上为编程提供方便。

五、 简化函数调用
1.  函数改名        Rename Method
    * 概述:修改函数名称
    * 动机:函数的名称未能表示函数的意图

2. 增加参数        Add Parameter
    * 概述:为函数添加一个对象参数,让这个对象带进函数所需的信息
    * 动机:某个函数需要从调用端获取更多的信息

3. 移除参数         Remove Parameter
    * 概述:将函数参数移除
    * 动机:函数本体不在需要某个参数,而参数列表却有

4. 将查询函数和修改函数分离        Separate Query from modifier
    * 概述:建立两个不同的函数,其中一个负责修改,另一个负责查询
    * 动机:获取值得时候会修改函数值,会使得其他只需要取状态值得调用者关心更多的东西,从而产生副作用

5. 令函数携带参数        Parameterize Method
    * 概述:建立单一函数,以参数表达那些不同的值。
    * 动机:多个函数做着类似的工作,只是因为少数几参数,或者参数个数不同。则可以使用一个单一函数将他们统一起来,为这个函数增加携带参数

6. 以明确函数取代参数    Replace Parameter with Explicit Methods
    * 概述:针对该参数的每一个可能值,建立一个独立函数
    * 动机:有一个函数,取决于不同的参数值而采取不同的行为,这时可以为每个独立之建立一个独立函数。 某种程度与上一条相反

7. 保持对象完整        Preserve Whole Object
    * 概述:改为传递整个对象
    * 动机:从某个对象中取出若干值,并将他们作为某一次函数调用参数的时候,可以将参数修改为传递整个对象,以减少参数列表和对抗未来改动的风险。

8. 以函数取代参数     Replace Parameter with Methods
    * 概述:让参数接受者去除该项参数,并直接调用前一个函数
    * 动机:如果函数可以通过其他途径取得参数值,那么久不应该通过参数值获取。这样可以减少参数列表,从而减少局部变量。

9. 引入参数对象        Introduce Parameter Object
    * 概述:以一个对象取代这些参数
    * 动机:某些参数总是很自然的同时出现,当一组参数总是被同时传递给多个函数时候,则将这些参数整合成一个对象

10. 移除设置函数        Remove Setting Method
    * 概述:去掉字段中的所有设置函数
    * 动机:对象中的某个字段只应该在对象创建的时候被设置,然后就不再改变,则不因该提供设值函数,否则可能导致其值被修改,且容易混淆

11. 以工厂函数取代构造函数        Replace Constructor with Factory Method
    * 概述:将构造函数替换为工厂函数
    * 动机:通过静态工厂函数来生产对象,从而将对象生产权利把控在本类中,调用者完成不需要关系这个新对象的构建过程

12. 封装向下转形        Encapsulate Downcast
    * 概述:将向下转形动作移到函数中
    * 动机:某个函数返回的对象需要调用者自己强转类型。这是可以将强转类型封装在函数内部,使得调用者无需关心实际类型。需要该函数返回类型有限且确定。

13. 以异常取代错误码    Replace Error Code with Exception
    * 概述:将错误码改用异常
    * 动机:抛出异常能够更加清楚知道代码执行过程产生的问题。

14. 以测试取代异常    Replace Exception with Test
    * 概述:修改调用者,使它在调用函数之前先做检查
    * 动机:异常只应该用于哪些产生意料之外的错误行为,而不应该成为条件检查的替代品。可以提供一个可重复执行的测试函数,让调用者者调用前先检查某个条件,在测试函数中处理try catch

ps: 从上述方法可以看出,其最终都是为了减少函数间传参的复杂度,从而减少了局部变量个数,也就提高的代码清晰度。

第六章、处理概括关系
1. 字段上移    Pull Up Field
    * 概述:将字段移到超类
    * 动机:两个子类拥有相同的字段

2. 函数上移    Pull Up Method
    * 概述:将函数移动至超类
    * 动机:有些函数各个子类中产生完全相同的结果

3. 构造函数本体上移    Pull Up Constructor Body
    * 概述:在超类中新建一个构造函数,并在子类中调用她
    * 动机:各个子类中拥有本体几乎一致的构造函数

4. 字段下移    Push Down Field
    * 概述:将这个字段移动到需要她的类中
    * 动机:超类中某个字段只被部分子类用到,让数据与操作在同一个类中。

5. 提炼子类    Extract Subclass
    * 概述:新建一个子类,将只被某些实例用到特性移动该子类中
    * 动机:子类划分不够具体,不够细致,导致某个类包含过多本不该自己管理的东西,这是可以提炼一个新的子类。

6. 提炼超类    Extract Superclass
    * 概述:为两个类建立一个超类,将相同的特性移至超类
    * 动机:两个类具有相似的特性

7. 提炼接口    Extract Interface
    * 概述:将相同的子集提炼到一个独立接口中
    * 动机:1. 若干客户端使用类接口中的同一子集;2. 两个类的接口有部分相同。这两种情况都可以抽出一套共有接口。

8. 折叠继承体系    Collapse Hierachy
    * 概述:将继承体系合为一体,以消除继承体系
    * 动机:超类和子类,并没有太大的区别。        ps: 

9. 塑造模板函数    Form Template Method
    * 概述:模板模式,不再概述

10. 以委托取代继承    Replace Inheritance with Delegation
    * 概述:装饰模式,不再概述
    * 动机:没有继承关系的两个类使用继承,不仅没有代码复用,还继承了父类大堆不相干方法,容易造成混淆;对于抽象的方法还必须覆写。而装饰模式可以自主选择需要复用的方法。ps:非继承关系的扩展请使用装饰模式;有继承关系的扩展请使用继承

11. 以继承取代委托    Replace Delegation with Inheritance
    * 概述:对于有继承体系的仍然使用继承体系,这样可以复用父类的方法和字段。

第七章、大型重构
1. 梳理并分解继承体系    Tease Apart Inheritance
    * 概述:建立两个继承体系,并通过委托关系让其中一个可以调用另一个
    * 动机:某个继承体系同时承担两项责任,将此继承体系拆解,使得抽象的分类更清楚、细致从而提高类的复用率,并使代码更简洁。

2. 将过程设计转化为对象设计        Convert Procedural Design to Objects
    * 概述:将数据记录变成对象,将大块的行为分成小块,并将行为移入相关的对象中
    * 动机:将面向过程的代码重构为面向对象的风格。

3. 将领域和表述/显示分离    Separate Domain from Presentation
    * 概述:将领域逻辑分离出来,为他们建立独立的领域类
    * 动机:从GUI中抽离领域逻辑,从而做到与显示的分离。如MVC模式

4. 提炼继承体系    Extract Hierachy
    * 概述:建立继承体系,以一个子类表示一种特殊情况
    * 动机:有一个类做了太多的工作,其中一部分是大量的条件表达式完成的。


ps: 大型重构需要较高的对业务场景的抽象能力,使得分类更精确细致,从而提高代码的利用率,使得编码更简单,结构更加清楚。
这样一个细致的体系:
1. 具有很强的对抗变化能力,她将未来所有可能变化的风险,限定在一个子类,甚至一个函数当中;
2. 具有很强的扩展能力,只需要通过实现不同的子类来增加新的功能,既不影响原有结构,更不影响其清晰度。

猜你喜欢

转载自blog.csdn.net/qq_32250495/article/details/84785068