2021年7月15日 星期四

[設計模式] Builder Pattern 建造者模式 - 和 Factory 工廠相關模式又有什麼區別?

由於自己的工作中不曾使用過類似Builder Pattern的情境,

因此剛讀完並沒有特別深刻的體會與連結,

但我盡量地去找出能應用的場景應該是什麼,來加強這個Pattern的學習記憶。

Builder Pattern 建造者模式

我自己認為大話設計模式中Builder的第一個範例還不足以完全滿足建造者模式,

因為這個範例沒有明確的Product類別 (但也沒有一定的對或錯),

所以直接練習他第二個完整建造者模式的範例,請參考 Chapter_13.1

先來看類別圖:


說明一下個個類別負責的功能。

Prodduct:定義建立後要使用的產品物件應有什麼功能

ConcreteBuilder:定義建立產品物件時各個功能參數細節

Builder:規範所有的ConcreteBuilder應該要去執行的那些"建立參數細節"function。

Director:定義ConcreteBuilder內的建立function的執行順序


看到這邊,我想應該還是一頭霧水,再繼續來看細節部分。


來看Product內定義了什麼,

作者這個範例很簡單,只定義一個Add()來作為Product的功能

[所以我覺得這個範例並不是那麼直覺,很難聯想到實際應用情形。]













接著Builder定義出所有的ConcreteBuilder應該要實做的項目,

他們都必須實做PartA與PartB用以建立Product的Add() function,

而PartA與PartB的差異僅僅是參數的不同,細節定義在ConcreteBuilder中。







兩個ConcreteBuilder實作的細節如下,而這也是這個Pattern最重要的部分之一,

使用者可以定義多種不同的參數,隨時替換參數以建立出不同參數打造的Product物件。


可以觀察到ConcreteBuilderOne實作參數為hand與arm,

ConcreteBuilderTwo實作參數為leg與foot。

完成這些之後,來看這個Pattern另一個最重要的部分-Director

Director的實作定義了這些零組件的"建立順序",先建立PartB再組裝PartA:







到目前為止我們已經擁有了Builder Pattern中最重要的兩個元素,

"建立物件的參數"與"建立物件的順序"。

來看看使用者使用上會有什麼效果吧。

















由於我們已經在ConcreteBuilder定義好建立Product需要的參數了,

因此現在要透過Director去組裝,而組裝步驟也定義在Construct()中,

所以當使用者需要使用第一套參數(ConcreteBuilderOne)所建立的Product物件,依照以下步驟:

步驟一:

先把參數設定檔ConcreteBuilder建立出來,

步驟二:

再把這個參數設定檔交給Director去組裝成Product物件。


要切換成第二套參數也非常簡單,

依照上述兩個步驟就可以建立出完全不同屬性的Product物件了。

但我覺得這個例子很難連結到實際的應用情境。


實際(?)應用情境

如果套上我自己想像的情境,來看 Chapter_13.2 。我們把情境設定為,

Product是自動化機台的光學量測模組(Automated Optical Inspection , AOI),

而這個量測模組內有三個重要組件需要初始化建立,

分別是OpticalSensor 光學探頭、Stage 移動平台、Robot 機械手臂,

並假設我們使用的廠牌條列如下:

  • OpticalSensor 
    • OpticalBrand A
    • OpticalBrand B
  • Stage
    • StageBrand O
    • StageBrand P
  • Robot
    • RobotBrand Y
    • RobotBrand Z

因此Product類別就可以定義成以下類別:


















而經過測試,硬體的啟動順序必須為 Robot -> OpticalSensor -> Stage,

否則就會錯誤,

那我們就可以定義Director類別如下:









現在假設客戶Martin的機台硬體配置需求為:

OpticalSensor    選用 OpticalBrand A
Stage                  選用 StageBrand O
Robot                 選用 RobotBrand Y

而客戶Leo的機台硬體配置需求為:

OpticalSensor    選用 OpticalBrand B
Stage                  選用 StageBrand P
Robot                 選用 RobotBrand Z

那麼就可以為這兩位客戶各自建立一套Config參數,用以建立AOI產品,

Martin客戶的參數命名為ConfigOne,Leo客戶的命名參數為ConfigTwo,

ConfigOne類別定義如下:


















ConfigTwo類別定義如下:
















目前為止,我們已經準備好Builder Pattern最重要的兩個元素,

負責建立步驟的Director目標物件的參數設定AOI_ConfigBuilder

因此我們就可以透過Director來指揮AOI_ConfigBuilder建立出我們需要的AOI物件

來看看使用者如何呼叫:













如果仔細比較一下,可以發現如果已經有開發好的架構,

想要為不同的客戶替換不同廠牌的零件來使用這個架構時,

只需要幫這名客戶編寫一個ConfigBuilder類別,

再更換橘框中的參數類別即可,就可以穩定的產生一個AOI物件來使用,

而這邊又可以寫成 Strategy Pattern

讓使用者在Config檔案內設定好之後(例如開放一個.ini檔讓客戶修改),

啟動程式時就可以讀取Config檔內的參數,自動選擇要使用ConfigOne還是ConfigTwo,

而程式內就可以達成不必修改程式碼就執行想要的版本。


實作成本

不過寫成Builder Pattern的實作成本也滿高的,

看看檔案目錄內的AOI Builder Pattern資料夾與類別圖:
























目前只舉裡三種硬體設備,每個硬體設備只有兩種廠牌,也只有兩個ConcreteBuilder,

看起來就有點亂了,如果再龐大一點,不知道會長成什麼樣子,

所以使用Pattern也是需要付出代價的,所以才會有軟體架構師來專門負責這樣子的規劃吧。


與其他 Factroy Pattern 有什麼差異?

建造者是為了建立物件,那他和工廠相關Pattern有什麼不同?

我的想法是,工廠是為了集中"new"的地方,而建造者是關注"如何new",

"如何new"包含了new的順序參數

但我覺得建造者反而更像 Template Method 範本方法,都是規範子類如何進行操作,

    但他們之間的差異在哪呢?

    其實如果把範本方法類別中的那個範本方法取出來是不是就很像Director的功能?

    儘管兩者都是在規範子類進行一系列受規範的操作,

    但範本方法目的就僅止於規範操作步驟

    而製造者則是規範操作並以特定參數"生成"一個物件,最終目的是生成物件,

    因此兩個的目的是不同的。

沒有留言:

張貼留言

社會新鮮人如何投資?

我的觀點是,在 沒有很多 本錢 的情況下, 別寄望每個月幾千元放到股票或者最近很夯的高股息ETF就能讓你致富, 先投資自己,讓自己的本業收入提高吧。