---
# System prepended metadata

title: Design Pattern

---

# Design Pattern
[GoF Design Pattern](https://paginas.fe.up.pt/~aaguiar/as/gof/hires/patcafso.htm)

## Delegation
[2019.01.03]
http://best-practice-software-engineering.ifs.tuwien.ac.at/patterns/delegation.html

## Proxy
[2019.01.06]
>　Proxy to be a specialization of the more general delegation pattern. In the Proxy both the RealSubject and the Proxy conform to the same interface, this isn't the case with delegation.

virtual proxy: 可做些最架化措施，像是需要時才建立耗資源的物件

## Facade
[2019.01.09]

## Decorator
[2019.01.12]

#### **Applicability**
- 想動態而透明地添加額外權責到個別物件身上，不影響其他物件時
- 希望權責可動態撤銷時
- 想擴充功能，但子類別繼承方式卻不切實際時

#### **Pros**
- 比靜態的(多重)繼承機制更有彈性: 隨時把Decorator掛上去或拿掉，就能在執行期動態增刪權責
- 不必事先為用不到的功能付出代價，可以之後視實際需要以Decorator一點一點添加功能，且可疊加使用

#### **Cons**
- Decorator不等於Component，不能仰賴物件等同性質
- 小型物件太多了

#### **Implementation**
Decorator vs. Strategy [4]
1. Decorator是包在物件外面的一層皮；Strategy則是改變物件的內臟
2. 雖然Strategy方式可能得修改Component介面以留擴充餘地，不過Strategy介面的自由度很大，但Decorator的介面就受制於Component
3. Decorator是<font color=#0079c1>**由外往內**</font>改變Component，所以Component不必知道它被外覆(**Decorator對Component而言是透明的**)；至於Strategy，由於Component知道有哪些擴充項目，所以必須親自記錄及維護這些Strategy物件

## Strategy
[2019.01.14]

#### **Applicability**
- 如果許多相關類別僅在「行為」方面有別，可用Strategy併成一個類別，還可以自由切換行為
- 當你需要同一演算法的各種變形版本時(基於各種時間/空間考量)，可用Strategy將它們<font color=#0079c1>**組織成類別階級**</font>
- 若演算法用了不該被外界知悉的複雜資料結構時，可用Strategy避免曝光
- 如果一個類別裡定義了好幾種行為，且這些行為都是以條件判斷指令來切換時，最好把每一條分支搬到個別的Strategy類別身上

#### **Pros**
- 可定義一整族相關的演算法及行為讓Context選用，繼承機制可將各種演算法的共同功能抽取出來
- 不用把演算法時做細節混雜在Context裡(讓子類別繼承Context也能提供多種版本的演算法及行為)。改將演算法封裝在另一個Strategy類別，就可在不影響Context的情況下單獨改變引用的演算法，較易切換、理解、擴充
- 去除條件判斷式
- Strategy針對同一行為提供多種不同的實作，讓clients根據時間空間考量則一採用

#### **Cons**
- clients必須對各種不同的Strategy有所認知
- ConcreteStrategy共用同一個Strategy介面，有些東西對ConcreteStrategy來說可能稍嫌多餘(例如Context傳送的初始化參數)
- 物件數目增加

#### **Implementation**
Strategy獲得Context資訊的方式 [1]
1. Context主動把資料餵給Strategy(作為參數傳遞)，此時Strategy與Context耦合性較低，可是Context也可能送出Strategy所不需要的資料
2. 把Context自己當參數傳遞給Strategy，讓Strategy直接向Context索取想要的資料；Strategy也可以儲存一個指向Context的reference，但如此一來Context的介面就過於詳盡，Strategy和Context耦合度較高

## Flyweight
[2019.01.17]

#### **Applicability**
在以下條件<font color=#0079c1>**全都成立**</font>時才考慮用Flyweight
- 當應用程式使用了一大堆物件時
- 過多物件耗用過多空間時
- 物件的大部分狀態都可歸為外在狀態時
- 如果將外在狀態拿掉，就能將好幾群物件換成少數幾個共用物件時
- 如果應用程式並不仰賴物件等同性質時

#### **Pros**
- 共用的Flyweight物件越多就越省空間，可共用的狀態越多也越省空間；如果物件用了越多內在及外在狀態，且外在狀態可動態計算求得而不必存下來的話，就可省下最多的空間
因此可分為兩種途徑來解省空間:
    - 以共享物件降低內在狀態的空間代價
    - 以計算時間換取外在狀態的空間代價

#### **Implementation**
- 移除外在狀態: 此模式能否奏效，很大因素在於能否挑出外在狀態，從共用物件身上移出去
- 管理共用物件: 因為物件需要共用，所以外界不應該直接具現他們，應該用FlyweightFactory取得特定的Flyweight物件來用

## State
[2019.01.18]

#### **Applicability**
- 當物件的行為取決於它的狀態，連執行期行為也得隨狀態而改變時
- 如果某些操作裡面，依據物件狀態而做的條件判斷式太過於龐大時。狀態通常會以列舉常數表示，許多操作裡面也常會有相同的條件判斷結構。State將每一個條件分支抽取成獨立的類別，以便<font color=#0079c1>**將物件狀態也視為另一個獨立的物件**</font>，可獨立改變

#### **Pros**
- 集中處理與狀態相依的行為並予以切割: 每一個State子類別各封裝一種狀態轉移及動作，將程式執行狀態提升至整個物件狀態
- 突顯狀態轉移邏輯: 以Context的角度來看，狀態轉移應該是個不可再細分的atomic動作，觀念上只是重設一個State物件的變數而已
- 狀態物件可以共用: 如果State物件不含個體變數，Context就可共用State物件，此時State物件就相當於沒有內在狀態、只有行為的Flyweight物件

#### **Implementation**
1. 誰來定義狀態轉移邏輯? [1]
    - 如果轉移條件是固定的，就可全部寫在Context裡
    - 更彈性的作法，是讓State子類別自己只訂下一個State是誰、何時才做轉移；這得替Context增添一個介面，讓State物件能藉以設定Cotext的現行狀態
        - pros: 只要定義新的State子類別，就可修改或擴充狀態轉移邏輯
        - cons: State子類別需要知道至少一個其他的State子類別
2. 實作取捨 [3]
    - 有需要時才產生State物件，用完就殺掉
    - 事先就建立好，事後絕不殺掉

## Singleton
[2019.01.20]

#### **Applicability**
- 當類別只能有一個物件個體，而且還要給外界一個方便的單一窗口時
- 這唯一的物件個體必須也能透過繼承方式加以擴充，client不必修改就能使用新的擴充介面

#### **Pros**
- 掌控此為一個體的所有存取動作 
- 減少命名空間
- 操作和內部結構仍有擴充空間 
- 允許不定個體的物件個體 
- 比類別級操作更富彈性

#### **Implementation**
- 確保只會有一個物件個體存在: constructor記得要private

## Abstract Factory
[2019.01.22]

#### **Applicability**
- 當系統必須要和最終成品的生成、組合、表達方式保持獨立時
- 當系統組態必須能調整到與各陣營產品順利搭配時
- 一整族相關的物件必須一起使用，又得確保不會搭配錯誤
- 把類別程式庫貢獻出來，卻只想公開介面、不想公開實作細節

#### **Pros**
- 將具象類別隔離開來: 因為factory將創建成品物件的程序與責任封裝起來，將client隔絕在真正的實作類別之外，因此client只能透過抽象介面來操控這些物件
- 易於將整族成品物件抽換掉
- <font color=#0079c1>**增進成品物件的一致性**</font>: 若整族成品物件的設計初衷，本來就是該聚在一起使用，就有必要確保應用程式在同一時間只會使用某一物件陣營。Abstract Factory目的即在於此

#### **Cons**
- 難以提通新的成品物件種類: Abstract Factory的介面將「能產生哪幾種Product」寫死了；想擴充此介面，就得修該AbstractFactory類別及所有子類別

#### **Implementation**
 - 常與Factory Method搭配使用 [2、Sample Code]: 最常見的做法就是為每一種Product個定義一個factory method，然後各ConcreteFactory便可覆寫各自的factory method以產生特定的成品物件族系
 - 如果有好幾族成品物件同時並存，不妨採用Prototype模式來製作ConcreteFactory
 - AbstractFactory只是<font color=#0079c1>**一堆Factory Method的組合**</font> [Sample Code]
 - AbstractFactory(在Sample Code中)不是抽象類別，如此才能同時身兼AbstractFactory及ConcreteFactory二職 [Sample Code]

## Factory Method
[2019.01.25]

#### **Applicability**
- 當類別無法明指欲生成的物件類別時
- 當類別希望讓子類別去指定欲生成的物件類型時
- 當類別將權力下放給一個或多個輔助用途的子類別，又希望將「交付給那些子類別」的知識集中在一起時

#### **Pros**
- 有了Factory Method，就不必再將與應用場合高度相依的類別寫死在主程式裡。主程式只須面對Product介面，因此可和任何未知的ConcreteProduct類別合作無間
- Factory Method還有兩個作用:
    1. 替子類別預留掛勾: 子類別可以藉以擴增功能
    2. 連接平行地位的類別階層(類似Abstract Factory?): 平行地位類別階層通常會發生在「類別將某些權責委託給其他類別處理」的情況

#### **Cons**
- client必須自Creator類別衍生出子類別，才能造出特定的ConcreteProduct物件。如果不是本來就該衍生出子類別，就平白多一道手續

#### **Implementation**
- Factory Method有兩種主要形式
    1. Creator是抽象類別，Factory Method只是空殼子
    2. Creator是具象類別，Factory Method有預設行為(note: Java抽象類別的Method也可以用預設的行為)
- 參數化Factory Method: 讓同一個Factory Method能建立出多種成品物件。它有個指明生成物件「類型」的參數，所有能生成的物件都共享同一個Product介面(**不想處理的物件生成任務可以交還給父類別去完成**，參考[2])
- Factory Method常與lazy initialization併用[3]

## Prototype
[2019.01.28]
Objective-c將類別視為一級物件(first-class object): 任何物件都能當成creator來用，這類語言的class object本來就具有Prototype的性質 [Consequences 4]
first-calss object: 在執行期，class本身可以被當成參數傳入function或被function return
https://www.quora.com/What-are-first-class-objects

#### **Applicability**
- 當系統必須與成品物件的生成、組裝、表達方式保持獨立時[Abstract Factory Applicability 1]，**以及**下面**三種情況之一** :
    - 在執行期才指明欲具現哪一種類別時(如: 動態載入)；or
    - 避免造出與成品物件平行的一整族factory類別階層時；or
    - 當類別的物件個體只可能處於少數幾種可能的狀態時，替各種可能的狀態安置Prototype讓人複製，會比手動具現類別來得方便

#### **Pros**
- 在執行期增刪成品物件類型: 只要向client註冊Prototype，就能引進新的成品物件類型。client可以在執行期才安裝或卸除Prototype，較具彈性
- 改變內容已訂出新的物件: 可透過object composition方式制定新的行為，不須再定義新類別(先以既存類別具現出物件個體，再將它餵給client做prototype；client則有prototype可委託權責，以制定新行為) [2]
- 可減少系統所需的類別數量 [2]
- 改變結構以訂出新的物件: Composite物件的clone()採用deep copy [3]
- 減少子類別數量 [4]

#### **Cons**
- 每一個Prototype的子類別都必須實作clone()操作，未必是件容易的事

#### **Implementation**
- 使用Prototype manager
- Implementing the Clone operation: Prototype最困難的地方在於如何正確製作clone()
    - 萬一物件結構含有circular reference時不容易製作clone()
    - shallow copy versus deep copy: 以Prototype而言，萬一prototype的結構很複雜，就必須用deep copy才行，原物件和複製品才能各自獨立不相干擾
- Initializing clones(複製品): clone()通常不允許傳遞初始參數進去(為保持均一介面)。如果Prototype早已有設定狀態的操作，直接用它就行了，否則就得另外寫個initialize()來初始化複製品(Sample Code)

## Template Method
[2019.02.01]
Template Method vs. Strategy:
Template Method 利用繼承方式來改變演算法的某些部份
Strategy 則利用委託機制來改變整個演算法

#### **Applicability**
- 希望演算法的不變之處只寫一次，可變之處則留給子類別去實作時
- 如果許多子類別都會有些共同的行為，就應該抽取出來集中至另一個共同的類別，避免一再重複
- 希望能控制子類別的擴充範圍時。可以讓template method在某些定點呼叫hook operation，將可能的擴充範圍侷限在這些定點上

#### **Consequences**
- Template Method是一種基本的程式碼再利用技術
- Inversion of control(IOC)、「好萊塢原理」
- hook operations, which provide default behavior that subclasses can extend if necessary. A hook operation often does nothing by default.
- Template Method有必要明定<font color=#0079c1>**哪些操作是hook性質**</font>(可被覆寫)、<font color=#0079c1>**哪些是抽象操作**</font>(必須覆寫)

#### **Implementation**
- access control: 
    - TemplateMethod呼叫的PrimitiveOperation要是protected，確保只會被TemplateMethod呼叫到
    - 必須被子類別覆寫的PrimitiveOperation，都該宣告成abstract method
    - TemplateMethod本身不該被覆寫(Java可以宣告final)
- 減少PrimitiveOperation的數目: 盡可能減少子類別所需覆寫的PrimitiveOperation數目

## Composite
[2019.02.14]

#### **Applicability**
- 想表達出「部分-全體」的物件關係時
- 想讓客戶碼不須考慮基本物件與複合物件之間的差異，能以一致的方式處理複合結構裡的物件時

#### **Pros**
- 簡化client: client能以一致性的角度處理複合結構和個別物件，它通常不會知道所面對的是Leaf還是Composite
- 更容易添加新的Component類型，不需修改Client

#### **Cons**
- 太容易增加新的Component類型意謂著難以對Composite所能包含的Component類型設限

#### **Implementation**
- 父節點的reference: 設置一個由子節點指向父節點的reference，可簡化複合結構的巡訪及管理，通常會把這個reference擺在Component類別裡。另外要確保每一個子節點的reference都確實回指到它的上一層複合體 [1]
- Composite的其中一個目的是不讓client確知所面對的到底是Leaf還是Composite，Component類別應盡可能涵蓋Composite和Leaf可能會有的操作。Component類別通常會提供預設的行為，Leaf和Composite的子類別也會去覆寫它們 [3]
- 宣告管理子節點的操作會面臨安全性與通透性的取捨，此模式比較強調通透性[4]

## Chain of Responsibility
[2019.05.]
 