設計模式--Builder

一、概述
在軟件系統中,有時候面臨着“一個複雜對象”的創建工作,其通常由各個部分的子對象用一定的算法構成;由於需求的變化,這個複雜對象的各個部分經常面臨着劇烈的變化,但是將它們組合在一起的算法確相對穩定。如何應對這種變化?如何提供一種“封裝機制”來隔離出“複雜對象的各個部分”的變化,從而保持系統中的“穩定構建算法”不隨着需求改變而改變?這就是要說的建造者模式。
 
建造者模式可以將一個產品的內部表象與產品的生成過程分割開來,從而可以使一個建造過程生成具有不同的內部表象的產品對象。
 
對象性質的建造
有些情況下,一個對象會有一些重要的性質,在它們沒有恰當的值之前,對象不能作爲一個完整的產品使用。比如,一個電子郵件有發件人地址、收件人地址、主題、內容、附錄等部分,而在最起碼的收件人地址未被賦值之前,這個電子郵件不能發出。
有些情況下,一個對象的一些性質必須按照某個順序賦值纔有意義。在某個性質沒有賦值之前,另一個性質則無法賦值。這些情況使得性質本身的建造涉及到複雜的商業邏輯。
這時候,此對象相當於一個有待建造的產品,而對象的這些性質相當於產品的零件,建造產品的過程就是組合零件的過程。由於組合零件的過程很複雜,因此,這些"零件"的組合過程往往被"外部化"到一個稱作建造者的對象裏,建造者返還給客戶端的是一個全部零件都建造完畢的產品對象。
之所以使用"建造者"而沒有用"生成器"就是因爲用零件生產產品,"建造"更爲合適,"創建"或"生成"不太恰當。
 
二、意圖
將一個複雜對象的構建與其表示相分離,使得同樣的構建過程可以創建不同的表示。
 
三、Builder模式的結構
Builder:爲創建Product對象的各個部件指定抽象接口。
ConcreteBuilder:實現Builder的接口以構造和裝配該產品的各個部件,定義並明確它所創建的表示,並提供一個檢索產品的接口。
Director:構造一個使用Builer接口的對象。
Product:表示被構造的複雜對象。ConcreteBuilder創建該產品的內部表示並定義它的裝配過程,包含定義組成部件的類,以及將這些部件裝配成最終產品的接口。
 
四、舉例
// Builder pattern -- Structural example  

using System;
using System.Collections;

// "Director"
class Director
{
  // Methods
  public void Construct( Builder builder )
  {
    builder.BuildPartA();
    builder.BuildPartB();
  }

}


// "Builder"
abstract class Builder
{
  // Methods
  abstract public void BuildPartA();
  abstract public void BuildPartB();
  abstract public Product GetResult();
}


// "ConcreteBuilder1"
class ConcreteBuilder1 : Builder
{
  // Fields
  private Product product;

  // Methods
  override public void BuildPartA()
  {
    product = new Product();
    product.Add( "PartA" );
  }


  override public void BuildPartB()
  {
    product.Add( "PartB" );
  }


  override public Product GetResult()
  {
    return product;
  }

}


// "ConcreteBuilder2"
class ConcreteBuilder2 : Builder
{
  // Fields
  private Product product;

  // Methods
  override public void BuildPartA()
  {
    product = new Product();
    product.Add( "PartX" );
  }


  override public void BuildPartB()
  {
    product.Add( "PartY" );
  }


  override public Product GetResult()
  {
    return product;
  }

}


// "Product"
class Product
{
  // Fields
  ArrayList parts = new ArrayList();
 
  // Methods
  public void Add( string part )
  {
    parts.Add( part );
  }


  public void Show()
  {
    Console.WriteLine( " Product Parts -------" );
    foreachstring part in parts )
      Console.WriteLine( part );
  }

}


/// <summary>
/// Client test
/// </summary>

public class Client
{
  public static void Main( string[] args )
  {
    // Create director and builders
    Director director = new Director( );

    Builder b1 = new ConcreteBuilder1();
    Builder b2 = new ConcreteBuilder2();

    // Construct two products
    director.Construct( b1 );
    Product p1 = b1.GetResult();
    p1.Show();

    director.Construct( b2 );
    Product p2 = b2.GetResult();
    p2.Show();
  }

}

現在我們來分析一下上面的例子:
假設要組裝一輛自行車,並且自行車就是車輪和車架組成,自行車有永久牌和鳳凰牌
Builder對應於組裝自行車所使用的車輪和車架
ConcreteBuiler1對應於永久牌車輪和車架,同時可以返回一輛永久牌自行車,ConcreteBuiler2對應於鳳凰牌車輪和車架,同時可以返回一輛鳳凰牌自行車
Product對應於自行車
Director表示組裝過程
此時我們再來理解下面這句話:“在軟件系統中,有時候面臨着“一個複雜對象”的創建工作,其通常由各個部分的子對象用一定的算法構成;由於需求的變化,這個複雜對象的各個部分經常面臨着劇烈的變化,但是將它們組合在一起的算法確相對穩定。”
自行車就是“一個複雜對象”,它有車輪和車架組成,但不管車輪和車架這兩個部件怎麼變化,生產一輛自行車的過程是不會變的,即組裝過程是不會變的。
 
五、優點
1、建造者模式的“加工工藝”是暴露的,這樣使得建造者模式更加靈活。
2、解耦了組裝過程和創建具體部件,使得我們不用去關心每個部件是如何組裝的。--上面對自行車的分析可以很清楚的看出這點。
 
六、缺點
1、上面的第1點優點也可以說是建造者模式的缺點,因爲“加工工藝”的暴露,使此模式不太“優雅”。
七、適用性
1、需要生成的產品對象有複雜的內部結構。
2、需要生成的產品對象的屬性相互依賴,建造者模式可以強迫生成順序。
3、在對象創建過程中會使用到系統中的一些其它對象,這些對象在產品對象的創建過程中不易得到。
 
八、實現要點
1、建造者模式主要用於“分步驟構建一個複雜的對象”,在這其中“分步驟”是一個穩定的算法,而複雜對象的各個部分則經常變化。
2、產品不需要抽象類,特別是由於創建對象的算法複雜而導致使用此模式的情況下或者此模式應用於產品的生成過程,其最終結果可能差異很大,不大可能提煉出一個抽象產品類。
3、創建者中的創建子部件的接口方法不是抽象方法而是空方法,不進行任何操作,具體的創建者只需要覆蓋需要的方法就可以,但是這也不是絕對的,特別是類似文本轉換這種情況下,缺省的方法將輸入原封不動的輸出是合理的缺省操作。
4、前面我們說過的抽象工廠模式(Abtract Factory)解決“系列對象”的需求變化,Builder模式解決“對象部分”的需求變化,建造者模式常和組合模式(Composite Pattern)結合使用。
 
九、.Net Framework中的應用
C#中有一個類叫StringBuilder,輸入必要的信息後,就可以取出對應的String。(我們可以將Builder理解成電飯鍋,給這個Builder放進去米和水,經過Builder的BuildPart後,我們就可以取出香噴噴的米飯了。)
using System;
using System.Text;

class Exam
{
 public static void Main()
 {
  StringBuilder sb = new StringBuilder();
  sb.Append('a',2);
  sb.Append('b',3);
  sb.Append('c',4);
  Console.WriteLine(sb.ToString()); //打印出 aabbbcccc
  sb.Remove(0, sb.Length); //清除sb中的所有信息
 }

}
程序執行結果爲: aabbbcccc
 
十、總結
建造者模式的實質是解耦組裝過程和創建具體部件,使得我們不用去關心每個部件是如何組裝的。


參考文獻
《敏捷軟件開發-原則、模式與實踐》 Robert C. Martin
《.Net與設計模式》 甄鐳
《Java與模式》 閻宏
“網絡資源”
發佈了0 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章