2012年5月9日

白話 Design Pattern (四) Builder pattern


相較於工廠系列的模式,著重在該產生哪一個物件;我們也可能面臨到建構過程本身就複雜的狀況,這時如何組裝出一個物件就可能是要解決的問題了,這裡要提到的是建構者模式(Builder pattern)

以學生餐廳的例子,如果將聚焦在點餐櫃台的動作,我們發現服務人員在接獲點餐後,分別有以下幾個動作:

炒飯櫃台:1.放上餐盤 、2. 放上免洗筷與鐵湯匙、3.放上炒飯、4.放上附湯。

麵點櫃台:1.放上餐盤 、2. 放上筷子與長湯匙、3.放上麵品、4.放上飲料 。


想想看,怎麼作比較好?

1.這次的重點在餐點的產生過程比較複雜,最好能夠將過程侷限在服務人員身上,點餐的學生只要享用該完成品,不需知道,也不需參予整個過程。

2.仔細分析,櫃台人員都有相同的四個動作,抽象的描述為:
1) 放上餐盤、2) 放上餐具、3) 放上餐點、4) 放上附湯飲料。

3.所以我們可以想像,整個模型有兩個部分:

1)執行四個動作:這部分兩個櫃台都一樣,見下圖的點餐服務

2) 對四個動作的各自表述:有一個抽象的餐點Builder與繼承它的炒飯Builder、麵食Builder


故,Builder Pattern的類別圖如下:

其中的Director就是負責執行各步驟並產出產品,Builder則確保了其繼承者都會有N個步驟。也有人將Director合併到Builder內,成為一種較簡化的變形。而這個模式中的幾個建構步驟,也可能與工廠系列的模式合作。

總之,Builder模式的重點有:

1.生產的流程複雜,需要被封裝。

2.每個builder都有相同的N個步驟或零件(步驟有先後順序,零件則無)。


前述的用法,產品較類似套餐,即各步驟或零件是固定的,選了A套餐,便能決定了每個部分是什麼。但實務上,如果到速食店點餐,雖然有分:主餐、副食、飲料三個部分,但可能個部分都是消費者當下選擇的(主餐可選雞塊/漢堡/雞堡、副食可選薯條/薯餅...),那就不可能在設計時期(Design Time)把所有的組合Builder都寫好,而需要代入多個參數,像下列:

餐點 A = new 餐點Builder(主食.雞塊, 副食.薯條, 飲料.coca).build();

那麼,如果建構時所需的參數非常多,要怎麼辦?下例是使用了Fluent Interface的技巧,讓新增客戶資料時,可以像以下這樣,簡潔易讀。


客戶 A = new 客戶Builder()
            .Name("Rock")
            .email("xxx@ooo.com")
            .cellphone("09xx123456")
            .build();

大致的寫法是:


public class 客戶
{
   public 客戶(string ID, string Name, string email, string cellphone)
   {
    ...
   }
}

public class 客戶Builder
{
   private 客戶 _Customer;

   string _Name;
   string _email;
   string _cellphone;

   public string Name(string Name)
   {
      _Name = Name;
      return(this);
   }

   public string email(string email)
   {
      _email = email;
      return(this);
   }

   public string cellphone (string cellphone)
   {
      _cellphone = cellphone;
      return(this);
   }

   public 客戶 build()
   {
      _Customer = new 客戶(_Name, _email, _cellphone);
      return(_Customer);
   }

}


最後,如果有人因為看到Builder中包含了多個建置方法,而覺得會跟Abstract Factory搞混,這裡整理了Builder Pattern與Abstract Factory Pattern的不同:

1) Builder著重在隱藏複雜的建置步驟,最後只傳回一個產品。

2) Abstract Factory則是為了維護一系列產品的關聯,會產出某系列的多項產品。

3) Builder模式中,Client不需要認識各個零件的型態。(只要『吃』產出的餐點)

4) Abstract Factory中,Client認識各項的抽象型別或介面,並能使用它們。



1 則留言:

  1. 請問五和六跑去哪裡了QQ
    拜讀您的文章感覺受益無窮

    回覆刪除