# 重構-向模式前進<br/>Refactoring to Patterns
## 1. 為什麼寫這本書
### 1.1 過度設計(Over-Engineering)
### 1.2 模式萬靈丹(The Patterns Panacea)
### 1.3 設計不足(Under-Engineering)
### 1.4 測試驅動開發和持續重構(Test-Driven Development and Continuous Refactoring)
### 1.5 重構與模式(Refactoring and Patterns)
### 1.6 漸進式設計(Evolutionary Design)
---
## 2. 重構(Refactoring)
### 2.1 何謂重構(What Is Refactoring?)
### 2.2 什麼促使我們重構(What Motivates Us to Refactor?)
### 2.3 眾目睽睽(Many Eyes)
### 2.4 人類易讀的程式碼(Human-Readable Code)
### 2.5 保持程式碼簡潔(Keeping It Clean)
### 2.6 小步驟(Small Steps)
### 2.7 設計債(Design Debt)
Ward Cunningham 對設計債隱喻為財務。
沒有堅持做以下三件事,就會招致設計債:
* 移除重複碼。
* 簡化程式碼。
* 讓程式碼目的更明確。
### 2.8 演變出一個新體系架構(Evolving a New Architecture)
漸進式設計(evolutionary design)提供更好的方法
* 成立一個團隊。
* 以應用層(appliction layer)的需求來設計框架層(framework layer)。
* 持續利用重構來改善應用層和框架層。
### 2.9 複式重構與測試驅動式重構(Composite and Test-Driven Refactorings)
### 2.10 複式重構的好處(The Benefits of Composite Refactorings)
每一個複式重構都對準特定的某個 pattern,並有下列好處:
* 它們描述重構次序的完整規劃(an overall plan for a refactoring sequence)。
* 它們對於並非顯而易見的設計方向帶來啟發。
* 它們對 pattern 的實作提供深刻洞見。
### 2.11 重構工具(Refactoring Tools)
---
## 3. 模式(Patterns)
### 3.1 什麼是模式(What Is a Pattern?)
* 物件導向設計(object-oriented design)
* 物件導向分析(object-oriented analysis)
* 領域設計(domain design)
* 程序和組織設計(process and organizational design)
* 使者者介面設計(user interface design)
Alexander 每個 pattern 都是三部分組成的規則(three part rule):
* 描述情境(context)。
* 問題(problem)。
* 解決方案(solution)。
### 3.2 模式帶來的喜樂(Patterns Happy)
### 3.3 條條大路通模式(There Are Many Ways to Implement a Pattern)
### 3.4 重構成為、接近、遠離模式(Refactoring to, towards, and away from Patterns)
|Pattern|To (成為)| Towards (接近) |Away (遠離)|
| -------- | -------- | -------- |-------- |
| Adapter | Extract Adapter<br/>Unify Interfaces with Adapter |Unify Interfaces with Adapter||
|Builder|Encapsulate Composite with Builder|||
|Collecting Parameter|Move Accumulation to Collecting Parameter|||
|Command|Replace Conditional Dispatcher with Command |Replace Conditional Dispatcher with Command ||
|Composed Method|Composed Method|||
|Composite|Replace One/Many Distinctions with Composite<br/>Extract Composite<br/>Replace Implicit Tree with Composite||Encapsulate Composite with Builder|
|Creation Method|Replace Constructors with Creation Methods|||
|Decorator|Move Embellishment to Decorator|Move Embellishment to Decorator||
|Factory|Move Creation Knowledge to Factory<br/>Encapsulate Classes with Factory|||
|Factory Method|Introduce Polymorphic Creation with Factory Method|||
|Interpreter|Replace Implicit Language with Interpreter|||
|Iterator|||Move Accumulation to Visitor|
|Null Object|Introduce Null Object|||
|Observer|Replace Hard-Coded Notifications with Observer|Replace Hard-Coded Notifications with Observer||
|Singleton|Limit Instantiation with Singleton||Inline Singleton|
|State|Replace State-Altering Conditionals with State|Replace State-Altering Conditionals with State||
|Strategy|Replace Conditional Logic with Strategy|Replace Conditional Logic with Strategy||
|Template Method|Form Template Method|||
|Visitor|Move Accumulation to Visitor|Move Accumulation to Visitor||
### 3.5 模式會讓程式碼更複雜嗎?(Do Patterns Make Code More Complex?)
### 3.6 模式知識(Pattern Knowledge)
### 3.7 使用模式進行預先設計(Up-Front Design with Patterns)
---
## 4. 程式碼壞味道(Code Smells)
|Smell|Refactoring|
| -------- | -------- |
|Duplicated Code|Form Template Method<br/>Introduce Polymorphic Creation with Factory Method<br/>Chain Constructors<br/>Replace One/Many Distinctions with Composite<br/>Extract Composite<br/>Unify Interfaces with Adapter<br/>Introduce Null Object|
|Long Method|Compose Method<br/>Move Accumulation to Collecting Parameter <br/>Replace Conditional Dispatcher with Command <br/>Move Accumulation to Visitor<br/>Replace Conditional Logic with Strategy|
|Conditional Complexity|Replace Conditional Logic with Strategy <br/>Move Embellishment to Decorator<br/>Replace State-Altering Conditionals with State<br/>Introduce Null Object|
|Primitive Obsession|Replace Type Code with Class<br/>Replace State-Altering Conditionals with State<br/>Replace Conditional Logic with Strategy<br/>Replace Implicit Tree with Composite<br/>Replace Implicit Language with Interpreter<br/>Move Embellishment to Decorator<br/>Encapsulate Composite with Builder|
|Indecent Exposure|Encapsulate Classes with Factory|
|Solution Sprawl|Move Creation Knowledge to Factory|
|Alternative Classes with Different Interfaces|Unify Interfaces with Adapter|
|Lazy Class|Inline Singleton|
|Large Class|Replace Conditional Dispatcher with Command <br/>Replace State-Altering Conditionals with State<br/>Replace Implicit Language with Interpreter|
|Switch Statements|Replace Conditional Dispatcher with Command<br/>Move Accumulation to Visitor|
|Combinatorial Explosion|Replace Implicit Language with Interpreter|
|Oddball Solution|Unify Interfaces with Adapter|
### 4.1 重複的程式碼(Duplicated Code)
### 4.2 過長的函式(Long Method)
### 4.3 複雜的條件式(Conditional Complexity)
### 4.4 基本偏執(Primitive Obsession)
### 4.5 不當暴露(Indecent Exposure)
### 4.6 解法蔓生(Solution Sprawl)
### 4.7 貌異實同的類別(Alternative Classeswit hDifferent Interfaces)
### 4.8 冗員類別(Lazy Class)
### 4.9 過大的類(Large Class)
### 4.10 Switch 語句(Switch Statement)
### 4.11 組合爆炸(Combinatorial Explosion)
### 4.12 詭譎方案(Oddball Solution)
---
## 5. 一份 Refactorings to Patterns 名錄(A Catalog of Refactorings to Patterns)
### 5.1 重構的記錄形式(Format of the Refactorings)
### 5.2 本目錄中引用的項目(Projects Referenced in This Catalog)
#### 5.2.1 XMLBuilder
#### 5.2.2 HTMLParser
#### 5.2.3 貸款風險計算器
### 5.3 起點(A Starting Point)
### 5.4 學習順序(A Study Sequence)
|Session|Refactoring|
| -------- |-------- |
|1|Replace Constructors with Creation Methods<br/>Chain Constructors|
|2|Encapsulate Classes with Factory|
|3|Introduce Polymorphic Creation with Factory Method|
|4|Replace Conditional Logic with Strategy|
|5|Form Template Method|
|6|Compose Method|
|7|Replace Implicit Tree with Composite|
|8|Encapsulate Composite with Builder|
|9|Move Accumulation to Collecting Parameter|
|10|Extract Composite<br/>Replace One/Many Distinctions with Composite|
|11|Replace Conditional Dispatcher with Command|
|12|Extract Adapter<br/>Unify Interfaces with Adapter|
|13|Replace Type Code with Class|
|14|Replace State-Altering Conditionals with State|
|15|Introduce Null Object|
|16|Inline Singleton<br/>Limit Instantiation with Singleton|
|17|Replace Hard-Coded Notifications with Observer|
|18|Move Embellishment to Decorator<br/>Unify Interfaces<br/>Extract Parameter|
|19|Move Creation Knowledge to Factory|
|20|Move Accumulation to Visitor|
|21|Replace Implicit Language with Interpreter |
---
## 6. 創建(Creation)
### 6.1 Replace Constructors with Creation Methods<br/>以創建函式(Creation Methods)替代建構式(Contructors)
開發過程中為數眾多的 classes 建構式令客戶難以決定呼叫哪一個建構式。
以 目的清楚、返回物件實體 的 Creation Method 取代建構式。

#### 6.1.1 動機
當某些語言要求每個建構式都必須以其 class 名稱命名。
如果有多個建構式,客戶端必須選擇呼叫哪一個建構式,為此得研究參數,並在建構式源碼中摸索。
建構式無法有效傳遞目的。容易誤用某個建構式。當程式員必須選擇呼叫那個建構式時,會降低開發速度。
#### 6.1.2 做法
#### 6.1.3 示例
Loan.class
貸款風險計算器(loan risk calculator)
Loan class 有 7 種貸款(loan),這裡只討論其中三種。
* loan(貸款)
* revolver(循環信用貸款)
* revolving credit term loan(循環信用定期貸款)
```
public class Loan{
public Loan(double commitment, int riskRating, Date maturity) {
this(commitment, 0.00, riskRating, maturity, null);
}
public Loan(double commitment, int riskRating, Date maturity, Date expiry) {
this(commitment, 0.00, riskRating, maturity, expiry);
}
public Loan(double commitment, double outstanding,
int customerRating, Date maturity, Date expiry) {
this(null, commitment, outstanding, customerRating, maturity, expiry);
}
public Loan(CapitalStrategy capitalStrategy, double commitment,
int riskRating, Date maturity, Date expiry) {
this(capitalStrategy, commitment, 0.00, riskRating, maturity, expiry);
}
public Loan(CapitalStrategy capitalStrategy, double commitment,
double outstanding, int riskRating,
Date maturity, Date expiry) {
this.commitment = commitment;
this.outstanding = outstanding;
this.riskRating = riskRating;
this.maturity = maturity;
this.expiry = expiry;
this.capitalStrategy = capitalStrategy;
if (capitalStrategy == null) {
if (expiry == null)
this.capitalStrategy = new CapitalStrategyTermLoan();
else if (maturity == null)
this.capitalStrategy = new CapitalStrategyRevolver();
else
this.capitalStrategy = new CapitalStrategyRCTL();
}
}
```
##### Step 1
找出單元測試
```
public class CapitalCalculationTests
public void testTermLoanNoPayments() {
Loan termLoan = new Loan(commitment, riskRating, maturity);
}
```
##### Step 2
依照意圖(Intent)命名並建立新的函式
```
public class CapitalCalculationTests...
public void testTermLoanNoPayments() {
Loan termLoan = createTermLoan(commitment, riskRating, maturity);
}
public static Loan createTermLoan(double commitment, int riskRating, Date maturity) {
return new Loan(commitment, riskRating, maturity);
}
```
##### Step 3
將 createTermLoan 函式移到 Loan class。
將 CapitalCalculationTest class 中的 createTermLoan 函式刪除。
Loan.class
```
public class Loan{}
public static Loan createTermLoan(double commitment, int riskRating, Date maturity) {
return new Loan(commitment, riskRating, maturity);
}
```
CapitalCalculationTest.class
```
public class CapitalCalculationTest{
public void testTermLoanNoPayments() {
...
Loan termLoan = Loan.createTermLoan(commitment, riskRating, maturity);
...
}
```
##### 目標

為了達成上圖目標我試著還原完整的 Loan class
Loan.class
```
/**
* @author RainBowT
* Loan.class
* 貸款風險計算器(loan risk calculator)
* Loan class 有 7 種貸款(loan),這裡只討論其中三種。
* 1. loan(貸款)
* 2. revolver(循環信用貸款)
* 3. revolving credit term loan(循環信用定期貸款)
*/
public class Loan {
private double commitment;
private double outstanding;
private int riskRating;
private Date maturity;
private Date expiry;
private CapitalStrategy capitalStrategy;
public Loan(double commitment, int riskRating, Date maturity) {
this(commitment, 0.00, riskRating, maturity, null);
}
public Loan(double commitment, double outstanding, int riskRating, Date expiry) {
}
public Loan(double commitment, int riskRating, Date maturity, Date expiry) {
this(commitment, 0.00, riskRating, maturity, expiry);
}
public Loan(double commitment, double outstanding,
int customerRating, Date maturity, Date expiry) {
this(null, commitment, outstanding, customerRating, maturity, expiry);
}
public Loan(CapitalStrategy capitalStrategy, double commitment,
int riskRating, Date maturity, Date expiry) {
this(capitalStrategy, commitment, 0.00, riskRating, maturity, expiry);
}
public Loan(CapitalStrategy capitalStrategy, double commitment,
double outstanding, int riskRating, Date expiry) {
}
public Loan(CapitalStrategy capitalStrategy, double commitment,
double outstanding, int riskRating,
Date maturity, Date expiry) {
this.commitment = commitment;
this.outstanding = outstanding;
this.riskRating = riskRating;
this.maturity = maturity;
this.expiry = expiry;
this.capitalStrategy = capitalStrategy;
if (capitalStrategy == null) {
if (expiry == null) {
this.capitalStrategy = new CapitalStrategyTermLoan();
} else if (maturity == null) {
this.capitalStrategy = new CapitalStrategyRevolver();
} else {
this.capitalStrategy = new CapitalStrategyRCTL();
}
}
}
}
```
根據上 Loan class 可以發現根本搞不清楚哪種貸款要使用哪個建構式。
因此利用建立 public static 函式並利用建構式意圖命名函式能幫助開發人員選擇對應的建構式。
完整 Loan class
```
/**
* @author RainBowT
* Loan.class
* 貸款風險計算器(loan risk calculator)
* Loan class 有 7 種貸款(loan),這裡只討論其中三種。
* 1. loan(貸款)
* 2. revolver(循環信用貸款)
* 3. revolving credit term loan(循環信用定期貸款)
*/
public class Loan {
private double commitment;
private double outstanding;
private int riskRating;
private Date maturity;
private Date expiry;
private CapitalStrategy capitalStrategy;
public Loan(double commitment, int riskRating, Date maturity) {
this(commitment, 0.00, riskRating, maturity, null);
}
public Loan(double commitment, double outstanding, int riskRating, Date expiry) {
}
public Loan(double commitment, int riskRating, Date maturity, Date expiry) {
this(commitment, 0.00, riskRating, maturity, expiry);
}
public Loan(double commitment, double outstanding,
int customerRating, Date maturity, Date expiry) {
this(null, commitment, outstanding, customerRating, maturity, expiry);
}
public Loan(CapitalStrategy capitalStrategy, double commitment,
int riskRating, Date maturity, Date expiry) {
this(capitalStrategy, commitment, 0.00, riskRating, maturity, expiry);
}
public Loan(CapitalStrategy capitalStrategy, double commitment,
double outstanding, int riskRating, Date expiry) {
}
public Loan(CapitalStrategy capitalStrategy, double commitment,
double outstanding, int riskRating,
Date maturity, Date expiry) {
this.commitment = commitment;
this.outstanding = outstanding;
this.riskRating = riskRating;
this.maturity = maturity;
this.expiry = expiry;
this.capitalStrategy = capitalStrategy;
if (capitalStrategy == null) {
if (expiry == null) {
this.capitalStrategy = new CapitalStrategyTermLoan();
} else if (maturity == null) {
this.capitalStrategy = new CapitalStrategyRevolver();
} else {
this.capitalStrategy = new CapitalStrategyRCTL();
}
}
}
//------------------- Replace Constructors with Creation Methods --------------------//
public static Loan createTermLoan(double commitment, int riskRating, Date maturity) {
return new Loan(commitment, riskRating, maturity);
}
public static Loan createTermLoan(CapitalStrategy riskAdjustedCapitalStrategy,
double commitment, double outstanding, int riskRating, Date maturity) {
return new Loan(riskAdjustedCapitalStrategy, commitment,
outstanding, riskRating, maturity, null);
}
public static Loan createRevolver(double commitment, double outstanding, int riskRating, Date expiry) {
return new Loan(commitment, outstanding, riskRating, expiry);
}
public static Loan crateRevolver(CapitalStrategy capitalStrategy,
double commitment, double outstanding, int riskRating, Date expiry) {
return new Loan(capitalStrategy, commitment, outstanding, riskRating, expiry);
}
public static Loan createRCTL(double commitment, double outstanding, int riskRating, Date maturity, Date expiry) {
return new Loan(commitment, outstanding, riskRating, maturity, expiry);
}
public static Loan createRCTL(CapitalStrategy capitalStrategy,
double commitment, double outstanding, int riskRating, Date maturity, Date expiry) {
return new Loan(capitalStrategy, commitment, outstanding, riskRating, maturity, expiry);
}
}
```
#### 6.1.4 變體
Extract Factory

### 6.2 Move Creation Knowledge to Factory<br/>將創建知識(Creation Knowledge) 移至 Factory
用以具現(instantiate) class 的各種資料和程式碼蔓延於許多 classes。
把創建知識(creation knowledge) 搬移至單個 Factory class 中。

#### 6.2.1 動機
一旦物件的`創建知識`散於多個 classes 內,便是出現了 Creation Sprawl(創建碼蔓生)壞味道:不該在物件創建過程中扮演任何角色的 classes,其內卻出現創建任務(creational responsibility)。
#### 6.2.2 做法
#### 6.2.3 示例
### 6.3 Encapsulate Classes with Factory<br/>以 Factory 封裝眾多 Classes
客戶端直接具現 位於同一個 package 內並實作共同 interface 的 classes。
把 class 建構式改設為 non-public 並讓客戶端以 Factory 創建 classes 實體。

#### 6.3.1 動機
只要客戶端需要知曉`某些 classes 的實體存在全信息(very existence of those classes)`,客戶端直接具現那些 classes 的能力就有價值。但如果客戶不需要那些知識呢?
作法是讓一個 Factory 創建並返回`實作某共同介面`的實體。
#### 6.3.2 做法
#### 6.3.3 示例
AttributeDescriptor.class
```
public abstract class AttributeDescriptor{
protected AttributeDescriptor(){
}
}
```
BooleanDescriptor.class
```
public class BooleanDescriptor extends AttributeDescriptor{
public BooleanDescriptor() {
super();
}
}
```
DefaultDescriptor.class
```
public class DefaultDescriptor extends AttributeDescriptor{
public DefaultDescriptor() {
super();
}
}
```
ReferenceDescriptor.class
```
public class ReferenceDescriptor extends AttributeDescriptor{
public ReferenceDescriptor() {
super();
}
}
```
##### Step 1
確定可以建立以下的實體
```
protected List createAttributeDescriptors() {
List result = new ArrayList();
result.add(new DefaultDescriptor("remoteId", getClass(), Integer.TYPE));
result.add(new DefaultDescriptor("createdDate", getClass(), Date.class));
result.add(new DefaultDescriptor("lastChangedDate", getClass(), Date.class));
result.add(new ReferenceDescriptor("createdBy", getClass(), User.class,
RemoteUser.class));
result.add(new ReferenceDescriptor("lastChangedBy", getClass(), User.class,
RemoteUser.class));
result.add(new DefaultDescriptor("optimisticLockVersion", getClass(), Integer.TYPE));
return result;
}
```
##### Step 2
實施 Etract Method 產出一個名為 forInteger 的 static creation method
```
protected List createAttributeDescriptors() {
List result = new ArrayList();
result.add(forInteger("remoteId", getClass(), Integer.TYPE));
}
private DefaultDescriptor forInteger(String remoteId, Class<? extends AttributeDescriptor> aClass, Class<Integer> type) {
return new DefaultDescriptor("remoteId", aClass, type);
}
```
#### Step 3
目標
```
protected List newCreateAttributeDescriptors() {
List result = new ArrayList();
result.add(forInteger("remoteId", getClass(), Integer.TYPE));
result.add(forDate("createdDate", getClass(), Date.class));
result.add(forDate("lastChangedDate", getClass(), Date.class));
result.add(new ReferenceDescriptor("createdBy", getClass(), User.class,
RemoteUser.class));
result.add(new ReferenceDescriptor("lastChangedBy", getClass(), User.class,
RemoteUser.class));
result.add(forInteger("optimisticLockVersion", getClass(), Integer.TYPE));
return result;
}
private DefaultDescriptor forDate(String createdDate, Class<? extends AttributeDescriptor> aClass, Class<Date> dateClass) {
return new DefaultDescriptor(createdDate, aClass, dateClass);
}
private DefaultDescriptor forInteger(String remoteId, Class<? extends AttributeDescriptor> aClass, Class<Integer> type) {
return new DefaultDescriptor(remoteId, aClass, type);
}
```
#### 6.3.4 變體
### 6.4 Introduce Polymorphic Creation with Factory Method<br/>以 Factory Method 導入多型創建(Polymorphic Ctration)
繼承體系(hierarchy) 內的 classes 以類似方式實現某函式,其間的唯一差別只在物件創建手段(object creation step)。
為該函示製作單個 superclass 版本,稱為 Factory Method,專門負責處理物件的具現行為(instantiation)。

#### 6.4.1 動機
#### 6.4.2 做法
#### 6.4.3 示例
XMLBulider 允許客戶端輕鬆產生 XML。
而後發現還需要至一個 DOMBulider,類似 XMLBuilder。
令 DOMBuilderTest 實例 DOMBulider 而不是 XMLBuilder。
DOMBuilderTest.class
```
public class DOMBuilderTest {
private OutputBuilder builder;
public void testAddAboveRoot() {
String invalidResult =
"<orders>" +
"<order>" +
"</order>" +
"</orders>" +
"<customer>" +
"</customer>";
builder = new DOMBuilder("orders"); // used to be new XMLBuilder("orders")
builder.addBelow("order");
try {
builder.addAbove("customer");
fail("expecting java.lang.RuntimeException");
} catch (RuntimeException ignored) {}
}
private void fail(String s) {
}
}
```
DOMBulider 的一個關鍵設計目標,是讓它和 XMLBuilder 共享相同型別 : OutputBuilder。

##### step 1
將實例邏輯(instantiation logic)提煉為一個實例函式(instatiation method)。
DOMBuilderTest.class
```
public class DOMBuilderTest extends TestCase...
protected OutputBuilder createBuilder(String rootName) {
return new DOMBuilder(rootName);
}
public void testAddAboveRoot() {
String invalidResult =
"<orders>" +
"<order>" +
"</order>" +
"</orders>" +
"<customer>" +
"</customer>";
builder = createBuilder("orders");
builder.addBelow("order");
try {
builder.addAbove("customer");
fail("expecting java.lang.RuntimeException");
} catch (RuntimeException ignored) {}
}
```
##### step 2
XMLBuilderTest
```
public class XMLBuilderTest extends TestCase...
private OutputBuilder createBuilder(String rootName) {
return new XMLBuilder(rootName);
}
public void testAddAboveRoot() {
String invalidResult =
"<orders>" +
"<order>" +
"</order>" +
"</orders>" +
"<customer>" +
"</customer>";
builder = createBuilder("orders");
builder.addBelow("order");
try {
builder.addAbove("customer");
fail("expecting java.lang.RuntimeException");
} catch (RuntimeException ignored) {}
}
```
##### step 3
Extract Superclass
```
public class AbstractBuilderTest extends TestCase {
}
public class XMLBuilderTest extends AbstractBuilderTest...
public class DOMBuilderTest extends AbstractBuilderTest...
```
##### step 4
From Template Method
```
public class AbstractBuilderTest extends TestCase {
protected OutputBuilder builder;
}
public class XMLBuilderTest extends AbstractBuilderTest...
private OutputBuilder builder;
public class DOMBuilderTest extends AbstractBuilderTest...
private OutputBuilder builder;
```
abstract Method
```
public abstract class AbstractBuilderTest extends TestCase {
protected OutputBuilder builder;
protected abstract OutputBuilder createBuilder(String rootName);
}
```
pull up method
```
public void testAddAboveRoot() {
String invalidResult =
"<orders>" +
"<order>" +
"</order>" +
"</orders>" +
"<customer>" +
"</customer>";
builder = createBuilder("orders");
builder.addBelow("order");
try {
builder.addAbove("customer");
fail("expecting java.lang.RuntimeException");
} catch (RuntimeException ignored) {}
}
```
### 6.5 Encapsulate Composite with Builder<br/>以 Builder 封裝複合物(Composite)
建置一個複合物(building a Composite)
讓 Builder 處理所有細節,藉以簡化建置(bulid)。



#### 6.5.1 做法
#### 6.5.2 示例
#### 6.5.3 變體
### 6.6 Inline Singleton<br/>將 Singleton 內置化
程式碼需要存取物件,卻不需要用來存取該物件的全域點(global point)。
把 Singleton 特徵移至可儲存物件並且提供該物件之存取方法的 class 內,然後刪除 Singleton。

#### 6.6.1 動機
#### 6.6.2 做法
#### 6.6.3 示例
---
## 7. 簡化(Simplification)
### 7.1 Compose Method
無法迅速瞭解函式 methods 的邏輯。
把邏輯操作轉換為若干目的清楚且細目等級(detail level)相同的步驟。

#### 7.1.1 動機
#### 7.1.2 做法
#### 7.1.3 示例
### 7.2 Replace Conditional Logic with Strategy<br/>以 Strategy 替代條件邏輯(Conditional Logic)
函式內的條件邏輯控制某一計算工作的各種變異(variants)中的哪一個被執行。
為每個變異(variant)建立起一個 Strategy,然後將函式的計算工作委託(delegate)給 Strategy 實體。


strategy class

#### 7.2.1 動機
#### 7.2.2 做法
#### 7.2.3 示例
### 7.3 Move Embellishment to Decorator<br/>將修飾碼(embellishment code)移至 Decorator
有些程式碼提供修飾功能(provide an embellishment),用來提供 class 的核心任務(core reponsibility)。
將修飾碼(embelishment code)移至一個 Decorator 內。


#### 7.3.1 動機
#### 7.3.2 做法
#### 7.3.3 示例
### 7.4 Replace State-Altering Conditionals with State<br/>以 State 替代狀態變換語句
控制 物件狀態遷移(object's state transitions) 的條件句十分複雜。
拿用以處理特定狀態及狀態遷移的 state classes 取代條件句。



#### 7.4.1 動機
#### 7.4.2 做法
#### 7.4.3 示例
### 7.5 Replace Implicit Tree with Composite<br/>以 Composite 替代隱寓的樹狀結構
以 Composite 取代原始表述(primitive representation)

#### 7.5.1 動機
資料或程式碼如果不是很明顯地被建構成樹狀,但卻表現得很樹狀,便是形成一個所謂的 implicit tree。
#### 7.5.2 做法
#### 7.5.3 示例
### 7.6 Replace Conditional Dispatcher with Command<br/>以 Command 替代條件句派送器。
條件邏輯被用來派送請求(dispatch requestes)和執行行動(execute actions)。
為每個行動(action) 產生一個 Command。把 Commands 儲存在群集(collection)中,並以提取並執行 Commands 的程式碼取代條件邏輯。

#### 7.6.1 動機
#### 7.6.2 做法
#### 7.6.3 示例
---
## 8. 一般化(Generalization)
### 8.1 Form Template Method
兩個位於不同 subclasses 內的函式以相同次序執行類似但不完全相同的步驟。
將函式步驟提取至相同簽名式(signatures)的函式中,以此達成函式的一般化。然後上提(pull up)這些一般化函式,形成 Template Method。

#### 8.1.1 動機
#### 8.1.2 做法
#### 8.1.3 示例
### 8.2 Extract Composite
繼承體系中的 subclasses 實作出相同的 Composite。
提煉出一個 superclass,由它來實作 Composite。

#### 8.2.1 動機
#### 8.2.2 做法
#### 8.2.3 示例
### 8.3 Replace One/Many Distinctions with Composite<br/>以 Composite 取代 單/群差異
Class 使用不同的程式碼分別處理單物件和群物件。
運用 Composite 建立起既能處理單物件又能處理群物件的程式碼。

#### 8.3.1 動機
#### 8.3.2 做法
#### 8.3.3 示例
### 8.4 Replace Hard-Coded Notifications with Observer<br/>以 Observer 替代被寫死的通告行為
Subclasses 死板板地(hard-coded)通知另一個 class 單個實體(single instance)。
移除 subclsses,方式是讓它們的 superclass 能夠通知實現 Observer 介面之任何 class 的一或多個實體。


#### 8.4.1 動機
#### 8.4.2 做法
#### 8.4.3 示例
### 8.5 Unify Interfaces with Adapter<br/>以 Adapter 統一介面。
客戶(Clients)與兩個 classes 互動,以 Adapter 讓介面一致。

#### 8.5.1 動機
#### 8.5.2 做法
#### 8.5.3 示例
### 8.6 Extract Adapter
有個 class 配接(adapts)了某個 Component(組件)或 library (程式庫) 或 API (應用程式介面)或其他 entity(物體)的多重版本。
針對某一版提煉一個對應的 Adapter。

#### 8.6.1 動機
#### 8.6.2 做法
#### 8.6.3 示例
#### 8.6.4 變體
### 8.7 Replace Implicit Language with Interpreter<br/>以 Interpreter(直譯器)取代隱性語言
class 內為數眾多的函式兼備了一個隱性語言元素(elements of an implicit language)。
針對隱性語言的元素定義出 classes,使其實體可被結合構成可直譯語句(interpretable expressions)。

#### 8.7.1 動機
#### 8.7.2 做法
#### 8.7.3 示例
---
## 9. 保護(Protection)
### 9.1 Replace Type Code with Class<br/>以 Class 替代基本型別
某個欄位的型別無法保護自己免受不安全的賦值動作(unsafe assignments)和無價值的相等測試(invalid equality comparisons)。
讓欄位型別成為 class,得以對賦值動作和相等測試設限(constrain)。

#### 9.1.1 動機
#### 9.1.2 做法
#### 9.1.3 示例
### 9.2 Limit Instantiation with Singleton<br/>以 Singleton 限制實例次數
程式碼產生多份物體實體,導致耗用太多記憶體或降低系統效能。
以一個 Singleton 取代多份實體。

#### 9.2.1 動機
#### 9.2.2 做法
#### 9.2.3 示例
### 9.3 Introduce Null Object<br/>導入無作用物件(Null Object)
處理 null 欄位或 null 變數的邏輯重複出現,遍布整個程式碼。
以 Null Object 取代 null 邏輯。此物件提供適切的 null 行為。

Null Object 經常透過 subclassing 或實作 interface 的方式實現。

#### 9.3.1 動機
#### 9.3.2 做法
#### 9.3.3 示例
---
## 10. 積累(Accumulation)
## 10.1 Move Accumulation to Collecting Parameter<br/>將積累資訊的任務移交給 Collecting Parameter
有一個體積龐大的函式,把資訊積累至一個區域變數(local variable)內。
將結果積累至一個收集資訊用的參數(Collecting Parameter),此參數將被傳給本重新提煉出來的函式。

### 10.1.1 動機
### 10.1.2 做法
### 10.1.3 示例
## 10.2 Move Accumulation to Visitor<br/>將積累資訊的任務移交給 Visitor
有個函式從異質(heterogeneous)classes中積累資訊。
將積累任務移交給能拜訪每個 class 以積累資訊的 Visitor。

* 積累函式(accumlation method)負責從異質 classes 積累資訊。
* 外部積累函式(external accumulation method)存在於不屬於異質 class 的某個 class 內。
* 內部積累函式(internal accumulation method)則是存在於異質 classes 的某一個 class 內。
### 10.2.1 動機
### 10.2.2 做法
### 10.2.3 示例
---
## 11. 工具(Utilities)
### 11.1 Chain Constructors<br/>將建構式(Contructors)鏈結起來
把建構式鏈結起來,以獲得最少量重複碼。

#### 11.1.1 動機
#### 11.1.2 做法
#### 11.1.3 示例
### 11.2 Unify Interfaces<br/>將介面統一起來
需要讓一個 superclass 或 interface 擁有與 subclass 相同的介面。
在 subclass 身上找出 superclass/interface 缺少的所有 public 函式。把這些遺漏的函式加至 superclass 並令它們執行 null 行為。

#### 11.2.1 動機
#### 11.2.2 做法
#### 11.2.3 示例
### 11.3 Extract Parameter<br/>提煉參數
函式或建構式以區域內實例值賦予某個欄位。
賦予此欄位一個由客戶提供的參數,作法是將賦值敘述句的一部分提煉為參數。

#### 11.3.1 動機
#### 11.3.2 做法
#### 11.3.3 示例
## 專業術語
* 類別-責任-合作(Class-Responsibility-Collaboration)
* 漸進式設計(evolutionary design)
* 複式重構的好處(Composite Refactorings)
* 物件導向設計(object-oriented design)
* 物件導向分析(object-oriented analysis)
* 領域設計(domain design)
* 程序和組織設計(process and organizational design)
* 使者者介面設計(user interface design)
* Regustry Pattern(Patterns of Enterprise Application Architecture)
* Type-Safe Enum Pattern
* 外部積累函式(external accumulation methods)
## 待瞭解
* FIT 測試框架
* 以模式為引導的重構(pattern-directed refactorings)
## 相關書籍
[Alexander, PL] Alexander, Christopher. A Pattern Language. New York: Oxford University Press, 1977.
[Alexander, TWB] Alexander, Christopher. A Timeless Way of Building. New York: Oxford University Press, 1979.
[Anderson] Anderson, Bruce. "Null Object." UIUC Patterns Discussion Mailing List (patterns@cs.uiuc.edu), January 1995.
[Astels] Astels, David. Test-Driven Development, a Practical Guide. Upper Saddle River, NJ: Prentice Hall, 2003.
[Barzun] Barzun, Jacques. Simple and Direct, 4th ed. New York: HarperCollins, 2001.
[Beck, SBPP] Beck, Kent. Smalltalk Best Practice Patterns. Upper Saddle River, NJ: Prentice Hall, 1997.
[Beck, TDD] Beck, Kent. Test-Driven Development. Boston, MA: Addison-Wesley, 2002.
[Beck, XP] Beck, Kent. Extreme Programming Explained. Reading, MA: Addison-Wesley, 1999.
[Beck and Gamma] Beck, Kent, and Erich Gamma. JUnit Testing Framework. Available online at http://www.junit.org. See also Erich Gamma and Kent Beck, "JUnit: A Cook's Tour," Java Report, May 1999.
[Bloch] Bloch, Joshua. Effective Java. Boston, MA: Addison-Wesley, 2001.
[Cunningham] Cunningham, Ward. "Checks: A Pattern Language of Information Integrity." In Pattern Languages of Program Design, eds. James O. Coplien and Douglas C. Schmidt. Reading, MA: Addison-Wesley, 1995.
[DP] Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Reading, MA: Addison-Wesley, 1995.
[Evans] Evans, Eric. Domain-Driven Design. Boston, MA: Addison-Wesley, 2003.
[Foote and Yoder] Foote, Brian, and Joseph Yoder. "Big Ball of Mud." In Pattern Languages of Program Design IV, eds. Neil Harrison, Brian Foote, and Hans Rohnert. Boston, MA: Addison-Wesley, 2000.
[F] Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA: Addison-Wesley, 2000.
[Fowler, PEAA] Fowler, Martin. Patterns of Enterprise Application Architecture. Boston, MA: Addison-Wesley, 2003.
[Fowler, UD] Fowler, Martin. UML Distilled, 3rd ed. Boston, MA: Addison-Wesley, 2003.
[Gamma and Beck] Gamma, Erich, and Kent Beck. Contributing to Eclipse. Boston, MA: Addison-Wesley, 2003.
[Kerievsky, PI] Kerievsky, Joshua. "Pools of Insight: A Pattern Language for Study Groups." Available online at http://industriallogic.com/papers/kh.html.
[Kerievsky, PXP] Kerievsky, Joshua. "Patterns & XP." In Extreme Programming Examined, eds. Giancarlo Succi and Michele Marchesi. Boston, MA: Addison-Wesley, 2001.
[Parnas] Parnas, David. "On the Criteria to Be Used in Decomposing Systems into Modules." Communications of the ACM, 15(2), 1972.
[Roberts, Brant, and Johnson] Roberts, Don, John Brant, and Ralph Johnson. "A Refactoring Tool for Smalltalk." Available online at http://st-www.cs.uiuc.edu/~droberts/tapos/TAPOS.htm.
[Solomon] Solomon, Maynard. Mozart. New York: HarperCollins, 1995.
[Vlissides] Vlissides, John. "C++ Report." April 1998. Available online at http://www.research.ibm.com/designpatterns/pubs/ph-apr98.pdf.
[Woolf] Woolf, Bobby. "The Null Object Pattern." In Pattern Languages of Program Design III, eds. Robert C. Martin, Dirk Riehle, and Frank Buschmann. Reading, MA: Addison-Wesley, 1997.
## 參考文獻
https://www.informit.com
https://flylib.com
https://www.industriallogic.com
https://github.com/marcotesta
https://aquastripe.github.io/refactoring-to-patterns-notes/ch11/extract-parameter.html#%E7%AF%84%E4%BE%8B
###### tags: `Golden Notes`