auto commit
This commit is contained in:
172
notes/重构.md
172
notes/重构.md
@ -1,6 +1,6 @@
|
||||
<!-- GFM-TOC -->
|
||||
* [第一个案例](#第一个案例)
|
||||
* [重构原则](#重构原则)
|
||||
* [一、第一个案例](#一第一个案例)
|
||||
* [二、重构原则](#二重构原则)
|
||||
* [定义](#定义)
|
||||
* [为何重构](#为何重构)
|
||||
* [三次法则](#三次法则)
|
||||
@ -9,31 +9,31 @@
|
||||
* [何时不该重构](#何时不该重构)
|
||||
* [重构与设计](#重构与设计)
|
||||
* [重构与性能](#重构与性能)
|
||||
* [代码的坏味道](#代码的坏味道)
|
||||
* [1. Duplicated Code(重复代码)](#1-duplicated-code重复代码)
|
||||
* [2. Long Method(过长函数)](#2-long-method过长函数)
|
||||
* [3. Large Class(过大的类)](#3-large-class过大的类)
|
||||
* [4. Long Parameter List(过长的参数列表)](#4-long-parameter-list过长的参数列表)
|
||||
* [5. Divergent Change(发散式变化)](#5-divergent-change发散式变化)
|
||||
* [6. Shotgun Surgery(散弹式修改)](#6-shotgun-surgery散弹式修改)
|
||||
* [7. Feature Envy(依恋情结)](#7-feature-envy依恋情结)
|
||||
* [8. Data Clumps(数据泥团)](#8-data-clumps数据泥团)
|
||||
* [9. Primitive Obsession(基本类型偏执)](#9-primitive-obsession基本类型偏执)
|
||||
* [10. Switch Statements(switch 惊悚现身)](#10-switch-statementsswitch-惊悚现身)
|
||||
* [11. Parallel Inheritance Hierarchies(平行继承体系)](#11-parallel-inheritance-hierarchies平行继承体系)
|
||||
* [12. Lazy Class(冗余类)](#12-lazy-class冗余类)
|
||||
* [13. Speculative Generality(夸夸其谈未来性)](#13-speculative-generality夸夸其谈未来性)
|
||||
* [14. Temporary Field(令人迷惑的暂时字段)](#14-temporary-field令人迷惑的暂时字段)
|
||||
* [15. Message Chains(过度耦合的消息链)](#15-message-chains过度耦合的消息链)
|
||||
* [16. Middle Man(中间人)](#16-middle-man中间人)
|
||||
* [17. Inappropriate Intimacy(狎昵关系)](#17-inappropriate-intimacy狎昵关系)
|
||||
* [18. Alernative Classes with Different Interfaces(异曲同工的类)](#18-alernative-classes-with-different-interfaces异曲同工的类)
|
||||
* [19. Incomplete Library Class(不完美的类库)](#19-incomplete-library-class不完美的类库)
|
||||
* [20. Data Class(幼稚的数据类)](#20-data-class幼稚的数据类)
|
||||
* [21. Refused Bequest(被拒绝的馈赠)](#21-refused-bequest被拒绝的馈赠)
|
||||
* [22. Comments(过多的注释)](#22-comments过多的注释)
|
||||
* [构筑测试体系](#构筑测试体系)
|
||||
* [重新组织函数](#重新组织函数)
|
||||
* [三、代码的坏味道](#三代码的坏味道)
|
||||
* [1. 重复代码](#1-重复代码)
|
||||
* [2. 过长函数](#2-过长函数)
|
||||
* [3. 过大的类](#3-过大的类)
|
||||
* [4. 过长的参数列表](#4-过长的参数列表)
|
||||
* [5. 发散式变化](#5-发散式变化)
|
||||
* [6. 散弹式修改](#6-散弹式修改)
|
||||
* [7. 依恋情结](#7-依恋情结)
|
||||
* [8. 数据泥团](#8-数据泥团)
|
||||
* [9. 基本类型偏执](#9-基本类型偏执)
|
||||
* [10. switch 惊悚现身](#10-switch-惊悚现身)
|
||||
* [11. 平行继承体系](#11-平行继承体系)
|
||||
* [12. 冗余类](#12-冗余类)
|
||||
* [13. 夸夸其谈未来性](#13-夸夸其谈未来性)
|
||||
* [14. 令人迷惑的暂时字段](#14-令人迷惑的暂时字段)
|
||||
* [15. 过度耦合的消息链](#15-过度耦合的消息链)
|
||||
* [16. 中间人](#16-中间人)
|
||||
* [17. 狎昵关系](#17-狎昵关系)
|
||||
* [18. 异曲同工的类](#18-异曲同工的类)
|
||||
* [19. 不完美的类库](#19-不完美的类库)
|
||||
* [20. 幼稚的数据类](#20-幼稚的数据类)
|
||||
* [21. 被拒绝的馈赠](#21-被拒绝的馈赠)
|
||||
* [22. 过多的注释](#22-过多的注释)
|
||||
* [四、构筑测试体系](#四构筑测试体系)
|
||||
* [五、重新组织函数](#五重新组织函数)
|
||||
* [1. Extract Method(提炼函数)](#1-extract-method提炼函数)
|
||||
* [2. Inline Method(内联函数)](#2-inline-method内联函数)
|
||||
* [3. Inline Temp(内联临时变量)](#3-inline-temp内联临时变量)
|
||||
@ -43,7 +43,7 @@
|
||||
* [7. Remove Assigments to Parameters(移除对参数的赋值)](#7-remove-assigments-to-parameters移除对参数的赋值)
|
||||
* [8. Replace Method with Method Object(以函数对象取代函数)](#8-replace-method-with-method-object以函数对象取代函数)
|
||||
* [9. Subsititute Algorithn(替换算法)](#9-subsititute-algorithn替换算法)
|
||||
* [在对象之间搬移特性](#在对象之间搬移特性)
|
||||
* [六、在对象之间搬移特性](#六在对象之间搬移特性)
|
||||
* [1. Move Method(搬移函数)](#1-move-method搬移函数)
|
||||
* [2. Move Field(搬移字段)](#2-move-field搬移字段)
|
||||
* [3. Extract Class(提炼类)](#3-extract-class提炼类)
|
||||
@ -52,7 +52,7 @@
|
||||
* [6. Remove Middle Man(移除中间人)](#6-remove-middle-man移除中间人)
|
||||
* [7. Introduce Foreign Method(引入外加函数)](#7-introduce-foreign-method引入外加函数)
|
||||
* [8. Introduce Local Extension(引入本地扩展)](#8-introduce-local-extension引入本地扩展)
|
||||
* [重新组织数据](#重新组织数据)
|
||||
* [七、重新组织数据](#七重新组织数据)
|
||||
* [1. Self Encapsulate Field(自封装字段)](#1-self-encapsulate-field自封装字段)
|
||||
* [2. Replace Data Value with Object(以对象取代数据值)](#2-replace-data-value-with-object以对象取代数据值)
|
||||
* [3. Change Value to Reference(将值对象改成引用对象)](#3-change-value-to-reference将值对象改成引用对象)
|
||||
@ -69,7 +69,7 @@
|
||||
* [14. Replace Type Code with Subcalsses(以子类取代类型码)](#14-replace-type-code-with-subcalsses以子类取代类型码)
|
||||
* [15. Replace Type Code with State/Strategy (以 State/Strategy 取代类型码)](#15-replace-type-code-with-statestrategy-以-statestrategy-取代类型码)
|
||||
* [16. Replace Subclass with Fields(以字段取代子类)](#16-replace-subclass-with-fields以字段取代子类)
|
||||
* [简化条件表达式](#简化条件表达式)
|
||||
* [八、简化条件表达式](#八简化条件表达式)
|
||||
* [1. Decompose Conditional(分解条件表达式)](#1-decompose-conditional分解条件表达式)
|
||||
* [2. Consolidate Conditional Expression(合并条件表达式)](#2-consolidate-conditional-expression合并条件表达式)
|
||||
* [3. Consolidate Duplicate Conditional Fragments (合并重复的条件片段)](#3-consolidate-duplicate-conditional-fragments-合并重复的条件片段)
|
||||
@ -78,7 +78,7 @@
|
||||
* [6. Replace Conditional with Polymorphism (以多态取代条件表达式)](#6-replace-conditional-with-polymorphism-以多态取代条件表达式)
|
||||
* [7. Introduce Null Object(引入Null对象)](#7-introduce-null-object引入null对象)
|
||||
* [8. Introduce Assertion(引入断言)](#8-introduce-assertion引入断言)
|
||||
* [简化函数调用](#简化函数调用)
|
||||
* [九、简化函数调用](#九简化函数调用)
|
||||
* [1. Rename Method(函数改名)](#1-rename-method函数改名)
|
||||
* [2. Add Parameter(添加参数)](#2-add-parameter添加参数)
|
||||
* [3. Remove Parameter(移除参数)](#3-remove-parameter移除参数)
|
||||
@ -94,7 +94,7 @@
|
||||
* [13. Encapsulate Downcast(封装向下转型)](#13-encapsulate-downcast封装向下转型)
|
||||
* [14. Replace Error Code with Exception (以异常取代错误码)](#14-replace-error-code-with-exception-以异常取代错误码)
|
||||
* [15. Replace Exception with Test(以测试取代异常)](#15-replace-exception-with-test以测试取代异常)
|
||||
* [处理概括关系](#处理概括关系)
|
||||
* [十、处理概括关系](#十处理概括关系)
|
||||
* [1. Pull Up Field(字段上移)](#1-pull-up-field字段上移)
|
||||
* [2. Pull Up Method(函数上移)](#2-pull-up-method函数上移)
|
||||
* [3. Pull Up Constructor Body(构造函数本体上移)](#3-pull-up-constructor-body构造函数本体上移)
|
||||
@ -110,7 +110,7 @@
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
# 第一个案例
|
||||
# 一、第一个案例
|
||||
|
||||
如果你发现自己需要为程序添加一个特性,而代码结构使你无法很方便地达成目的,那就先重构这个程序。
|
||||
|
||||
@ -173,7 +173,7 @@ double getTotalCharge() {
|
||||
|
||||
<div align="center"> <img src="../pics//2c8a7a87-1bf1-4d66-9ba9-225a1add0a51.png"/> </div><br>
|
||||
|
||||
# 重构原则
|
||||
# 二、重构原则
|
||||
|
||||
## 定义
|
||||
|
||||
@ -229,13 +229,15 @@ double getTotalCharge() {
|
||||
|
||||
应当只关注关键代码的性能,因为只有一小部分的代码是关键代码。
|
||||
|
||||
# 代码的坏味道
|
||||
# 三、代码的坏味道
|
||||
|
||||
本章主要介绍一些不好的代码,也就是说这些代码应该被重构。
|
||||
|
||||
文中提到的具体重构原则可以先忽略。
|
||||
|
||||
## 1. Duplicated Code(重复代码)
|
||||
## 1. 重复代码
|
||||
|
||||
> Duplicated Code
|
||||
|
||||
同一个类的两个函数有相同表达式,则用 Extract Method 提取出重复代码;
|
||||
|
||||
@ -245,7 +247,9 @@ double getTotalCharge() {
|
||||
|
||||
如果两个毫不相关的类出现重复代码,则使用 Extract Class 方法将重复代码提取到一个独立类中。
|
||||
|
||||
## 2. Long Method(过长函数)
|
||||
## 2. 过长函数
|
||||
|
||||
> Long Method
|
||||
|
||||
函数应该尽可能小,因为小函数具有解释能力、共享能力、选择能力。
|
||||
|
||||
@ -255,111 +259,151 @@ Extract Method 会把很多参数和临时变量都当做参数,可以用 Repl
|
||||
|
||||
条件和循环语句往往也需要提取到新的函数中。
|
||||
|
||||
## 3. Large Class(过大的类)
|
||||
## 3. 过大的类
|
||||
|
||||
> Large Class
|
||||
|
||||
应该尽可能让一个类只做一件事,而过大的类做了过多事情,需要使用 Extract Class 或 Extract Subclass。
|
||||
|
||||
先确定客户端如何使用该类,然后运用 Extract Interface 为每一种使用方式提取出一个接口。
|
||||
|
||||
## 4. Long Parameter List(过长的参数列表)
|
||||
## 4. 过长的参数列表
|
||||
|
||||
> Long Parameter List
|
||||
|
||||
太长的参数列表往往会造成前后不一致,不易使用。
|
||||
|
||||
面向对象程序中,函数所需要的数据通常内在宿主类中找到。
|
||||
|
||||
## 5. Divergent Change(发散式变化)
|
||||
## 5. 发散式变化
|
||||
|
||||
> Divergent Change
|
||||
|
||||
设计原则:一个类应该只有一个引起改变的原因。也就是说,针对某一外界变化所有相应的修改,都只应该发生在单一类中。
|
||||
|
||||
针对某种原因的变化,使用 Extract Class 将它提炼到一个类中。
|
||||
|
||||
## 6. Shotgun Surgery(散弹式修改)
|
||||
## 6. 散弹式修改
|
||||
|
||||
> Shotgun Surgery
|
||||
|
||||
一个变化引起多个类修改;
|
||||
|
||||
使用 Move Method 和 Move Field 把所有需要修改的代码放到同一个类中。
|
||||
|
||||
## 7. Feature Envy(依恋情结)
|
||||
## 7. 依恋情结
|
||||
|
||||
> Feature Envy
|
||||
|
||||
一个函数对某个类的兴趣高于对自己所处类的兴趣,通常是过多访问其它类的数据,
|
||||
|
||||
使用 Move Method 将它移到该去的地方,如果对多个类都有 Feature Envy,先用 Extract Method 提取出多个函数。
|
||||
|
||||
## 8. Data Clumps(数据泥团)
|
||||
## 8. 数据泥团
|
||||
|
||||
> Data Clumps
|
||||
|
||||
有些数据经常一起出现,比如两个类具有相同的字段、许多函数有相同的参数,这些绑定在一起出现的数据应该拥有属于它们自己的对象。
|
||||
|
||||
使用 Extract Class 将它们放在一起。
|
||||
|
||||
## 9. Primitive Obsession(基本类型偏执)
|
||||
## 9. 基本类型偏执
|
||||
|
||||
> Primitive Obsession
|
||||
|
||||
使用类往往比使用基本类型更好,使用 Replace Data Value with Object 将数据值替换为对象。
|
||||
|
||||
## 10. Switch Statements(switch 惊悚现身)
|
||||
## 10. switch 惊悚现身
|
||||
|
||||
> Switch Statements
|
||||
|
||||
具体参见第一章的案例。
|
||||
|
||||
## 11. Parallel Inheritance Hierarchies(平行继承体系)
|
||||
## 11. 平行继承体系
|
||||
|
||||
> Parallel Inheritance Hierarchies
|
||||
|
||||
每当为某个类增加一个子类,必须也为另一个类相应增加一个子类。
|
||||
|
||||
这种结果会带来一些重复性,消除重复性的一般策略:让一个继承体系的实例引用另一个继承体系的实例。
|
||||
|
||||
## 12. Lazy Class(冗余类)
|
||||
## 12. 冗余类
|
||||
|
||||
> Lazy Class
|
||||
|
||||
如果一个类没有做足够多的工作,就应该消失。
|
||||
|
||||
## 13. Speculative Generality(夸夸其谈未来性)
|
||||
## 13. 夸夸其谈未来性
|
||||
|
||||
> Speculative Generality
|
||||
|
||||
有些内容是用来处理未来可能发生的变化,但是往往会造成系统难以理解和维护,并且预测未来可能发生的改变很可能和最开始的设想相反。因此,如果不是必要,就不要这么做。
|
||||
|
||||
## 14. Temporary Field(令人迷惑的暂时字段)
|
||||
## 14. 令人迷惑的暂时字段
|
||||
|
||||
> Temporary Field
|
||||
|
||||
某个字段仅为某种特定情况而设,这样的代码不易理解,因为通常认为对象在所有时候都需要它的所有字段。
|
||||
|
||||
把这种字段和特定情况的处理操作使用 Extract Class 提炼到一个独立类中。
|
||||
|
||||
## 15. Message Chains(过度耦合的消息链)
|
||||
## 15. 过度耦合的消息链
|
||||
|
||||
> Message Chains
|
||||
|
||||
一个对象请求另一个对象,然后再向后者请求另一个对象,然后...,这就是消息链。采用这种方式,意味着客户代码将与对象间的关系紧密耦合。
|
||||
|
||||
改用函数链,用函数委托另一个对象来处理。
|
||||
|
||||
## 16. Middle Man(中间人)
|
||||
## 16. 中间人
|
||||
|
||||
> Middle Man
|
||||
|
||||
中间人负责处理委托给它的操作,如果一个类中有过多的函数都委托给其它类,那就是过度运用委托,应当 Remove Middle Man,直接与负责的对象打交道。
|
||||
|
||||
## 17. Inappropriate Intimacy(狎昵关系)
|
||||
## 17. 狎昵关系
|
||||
|
||||
> Inappropriate Intimacy
|
||||
|
||||
两个类多于亲密,花费太多时间去探讨彼此的 private 成分。
|
||||
|
||||
## 18. Alernative Classes with Different Interfaces(异曲同工的类)
|
||||
## 18. 异曲同工的类
|
||||
|
||||
> Alernative Classes with Different Interfaces
|
||||
|
||||
两个函数做同一件事,却有着不同的签名。
|
||||
|
||||
使用 Rename Method 根据它们的用途重新命名。
|
||||
|
||||
## 19. Incomplete Library Class(不完美的类库)
|
||||
## 19. 不完美的类库
|
||||
|
||||
> Incomplete Library Class
|
||||
|
||||
类库的设计者不可能设计出完美的类库,当我们需要对类库进行一些修改时,可以使用以下两种方法:如果只是修改一两个函数,使用 Introduce Foreign Method;如果要添加一大堆额外行为,使用 Introduce Local Extension。
|
||||
|
||||
## 20. Data Class(幼稚的数据类)
|
||||
## 20. 幼稚的数据类
|
||||
|
||||
> Data Class
|
||||
|
||||
它只拥有一些数据字段,以及用于访问这些字段的函数,除此之外一无长物。
|
||||
|
||||
找出字段使用的地方,然后把相应的操作移到 Data Class 中。
|
||||
|
||||
## 21. Refused Bequest(被拒绝的馈赠)
|
||||
## 21. 被拒绝的馈赠
|
||||
|
||||
> Refused Bequest
|
||||
|
||||
子类不想继承超类的所有函数和数据。
|
||||
|
||||
为子类新建一个兄弟类,不需要的函数或数据使用 Push Down Method 和 Push Down Field 下推给那个兄弟。
|
||||
|
||||
## 22. Comments(过多的注释)
|
||||
## 22. 过多的注释
|
||||
|
||||
> Comments
|
||||
|
||||
使用 Extract Method 提炼出需要注释的部分,然后用函数名来解释函数的行为。
|
||||
|
||||
# 构筑测试体系
|
||||
# 四、构筑测试体系
|
||||
|
||||
Java 可以使用 Junit 进行单元测试。
|
||||
|
||||
@ -371,7 +415,7 @@ Java 可以使用 Junit 进行单元测试。
|
||||
|
||||
应当集中测试可能出错的边界条件。
|
||||
|
||||
# 重新组织函数
|
||||
# 五、重新组织函数
|
||||
|
||||
## 1. Extract Method(提炼函数)
|
||||
|
||||
@ -473,7 +517,7 @@ int discount (int inputVal, int quentity, int yearToDate){
|
||||
|
||||
## 9. Subsititute Algorithn(替换算法)
|
||||
|
||||
# 在对象之间搬移特性
|
||||
# 六、在对象之间搬移特性
|
||||
|
||||
## 1. Move Method(搬移函数)
|
||||
|
||||
@ -547,7 +591,7 @@ Hide Delegate 有很大好处,但是它的代价是:每当客户要使用受
|
||||
|
||||
和 Introduce Foreign Method 目的一样,但是 Introduce Local Extension 通过建立新的类来实现。有两种方式:子类或者包装类,子类就是通过继承实现,包装类就是通过组合实现。
|
||||
|
||||
# 重新组织数据
|
||||
# 七、重新组织数据
|
||||
|
||||
## 1. Self Encapsulate Field(自封装字段)
|
||||
|
||||
@ -658,7 +702,7 @@ public 字段应当改为 private,并提供相应的访问函数。
|
||||
|
||||
<div align="center"> <img src="../pics//f2e0cee9-ecdc-4a96-853f-d9f6a1ad6ad1.jpg"/> </div><br>
|
||||
|
||||
# 简化条件表达式
|
||||
# 八、简化条件表达式
|
||||
|
||||
## 1. Decompose Conditional(分解条件表达式)
|
||||
|
||||
@ -805,7 +849,7 @@ double getExpenseLimit() {
|
||||
}
|
||||
```
|
||||
|
||||
# 简化函数调用
|
||||
# 九、简化函数调用
|
||||
|
||||
## 1. Rename Method(函数改名)
|
||||
|
||||
@ -980,7 +1024,7 @@ double getValueForPeriod(int periodNumber) {
|
||||
return values[periodNumber];
|
||||
```
|
||||
|
||||
# 处理概括关系
|
||||
# 十、处理概括关系
|
||||
|
||||
## 1. Pull Up Field(字段上移)
|
||||
|
||||
|
Reference in New Issue
Block a user