My friends, my life, my style - James S.F. Hsieh

2/25/2011

常常搞混的 Structural pattern

以下幾種 structural pattern 常常被搞混或是誤用, 甚至都以 wrapper 這個濫用的名詞來稱呼, 大多都有 aggregation 的結構關係, 其 aggregate 的目有所不同, 以下以 caller, aggregator 與 target 來說明三者的關係

  1. Shortcut (一種退化的 Facade)
    aggregator 的目的是讓 caller 對 target 使用起來更簡單方便, aggregator 大多隱藏了很多操作 target 的細節, 所以具有減化複雜度的效果, 但是其目的是以 caller 方便為出發點, 所以 aggregator 多半參雜過多 caller 的假設與邏輯而變的不容易 maintain, 另外, 如果 target 提供一個新的功能, aggregator 往往都要對映的 "開一條路" 讓 caller 使用, 如果開路的代價比方便的好處高, 這就成為一種不良的設計 middle men.

    C# 有一種 syntax sugar Extension methods 可以避面這種 middle men 的問題, 又可以將操作的邏輯封裝在 caller 的部分而非獨立建立出一組 aggregator class.

  2. Proxy
    aggregator 的目的表留一種間接性來達到某種 target 沒有的功能, 這些功能跟 target 本身的功能通常比較沒有直接相關 (但不是絕對), 多半 aggregator 都是 transparent, 並且它會針對特定 target 來設計, 所以擁有相同的介面, 以下是一些比較著名的應用: 

    virtual proxy: 用於 lazy instantiation (visualization) 或是 lazy processing
    remote proxy: 用於 IPC/RPC proxy/stub, 用以支援遠端呼叫 
    access proxy: 用於 access control. COM 的 Apartment proxy/stub 就是一種 access proxy 用來保證對 target 的操作是 thread-safety

  3. Decorator
    當 target 有自己的繼承體系並且該體系擁有 composite pattern 結構, aggregator 的目的是擴充一些 target 沒有的功能 (sub-classing), 並且 aggregator 必須保有 composite 的特性, 所以它必須繼承 component 而非 target. 多半 aggregator 都是 transparent.

    proxy 跟 decorator 的目的嚴格說都是 sub-classing, 但是成本有時候比繼承還要高, 而 strategy 是一種比較低成本的做法, 但是這樣的機制必須被設計在 target 當中.

    Boost Iostreams library 與 WIC 提供 filter 的設計思維都是種 decorator pattern

  4. Adapter
    aggregator 的目的是讓 target 加入到 caller 的繼承體系中, 用以解決不相容的問題, 這種做法非常直覺, 因為幾乎沒有人想要在 caller 的繼承體系中實做一個跟 target 功能近似的 class. 而多半會 reuse target.

  5. Bridge
    aggregator 的目的是隔離抽象性實做, 所以 aggregator 必須定義一般性的抽像操作, 而 target 來實做細節, 一般來說 
    aggregator 會有自己的繼承體系, 並且 target 會有其對應關係, 不過, 繼承體系不一定是必要的 COM 的 interface 就是種例子, 繼承體系帶來的限制往往是弊多於利, 不如根據 aspect 分離 interface 是比較恰當的做法.

    如果一個 aggregator 會有多個可能的 target 實做對應, 那根據 target 來定義 
    aggregator (interface) 是種錯誤的思維, 這違反 DIP 與 bridge 的目的, 保持抽像性與分離不相依的面像才是介面設計的原則.