問題:
在軟體系統中,有時面臨著一個複雜物件的建立工作,通常是由很多其他的對象按一定的規則順序組合而成;由於需求的變化,這個複雜物件的各個部分經常面臨著劇烈的變化,但是將它們組合在一起的規則是相對穩定(結構和順序)。這時候我們需要把這個複雜物件的建立過程和這個對象的表示(展示)分離開來,使得可以使用同樣的構建過程建立不同的對象 表示。
定義:
將一個複雜物件的構建與其表示相分離,使得同樣的構建過程可以建立不同的表示。
意圖:
提供一個建造者Builder對象,他規定了建立一個複雜物件需要的組件,通過Director指定的建立規則,調用Builder中的具體組件,並指揮Builder返回一個具體的對象。
參與者:
•建造者(Builder):
為建立一個產品對象的各個組件指定抽象介面。一般會有兩種介面方法,一種介面用於規範產品的各個部分的組成,第二種介面用於返回建造後的產品。
•具體建造者(ConcreteBuilder):
實現Builder的介面,按具體的規則群組合複雜產品的各個組件,以及提供一個返回產品的介面。
•指揮者(Director):
指揮並構造一個使用Builder介面的對象。他只是在按照固定的流程規則將對象組合在一起。不關心組合產品的結果(複雜物件),和細節(子物件)。
•產品(Product):
表示被構造的複雜物件。
UML:
執行個體說明:
諾基亞手機工廠
公司定義了手機的生產步驟,交給生產部生產。
uml圖如下:
代碼:
/// <summary>
/// Builder 定義手機生產需要的組件(步驟)
/// </summary>
public abstract class BuilderPhone
{
public abstract void BuildMb();
public abstract void BuildCpu();
public abstract void SetSystem();
public abstract void Test();
public abstract Phone GetPhone();
}
/// <summary>
/// N8手機生產具體生產
/// </summary>
public class BuilderN8 : BuilderPhone
{
Phone n8;
public BuilderN8()
{
n8 = new Phone();
n8.PhoneName = "N8";
}
public override void BuildMb()
{
n8.Mb = "N8_2.0";
System.Console.WriteLine("N8主板安裝完成!");
}
public override void BuildCpu()
{
n8.Cpu = "ARM_C28";
System.Console.WriteLine("N8 CPU 安裝完成!");
}
public override void SetSystem()
{
n8.System = "塞班S60第三版";
System.Console.WriteLine("N8 系統 安裝完成!");
}
public override void Test()
{
n8.TestStatus = true;
System.Console.WriteLine("N8 測試完成!");
}
public override Phone GetPhone()
{
return n8;
}
}
/// <summary>
/// 指揮者 指揮 一個手機的 建立步驟 (是,先安裝記憶體 還是先安裝主板。。。)
/// </summary>
public class DirectorBuilderPhone
{
public void Construct(BuilderPhone builderPhone)
{
//先安裝主板
builderPhone.BuildMb();
//安裝CPU
builderPhone.BuildCpu();
//安裝系統
builderPhone.SetSystem();
//測試
builderPhone.Test();
}
}
/// <summary>
/// 具體的產品
/// </summary>
public class Phone
{
public String PhoneName { get; set; }
public String Mb { get; set; }
public String Cpu { get; set; }
public String System { get; set; }
public bool TestStatus { get; set; }
}
/// <summary>
/// 用戶端測試代碼
/// </summary>
public void BuilderTest()
{
//執行個體化一個指揮者
DirectorBuilderPhone dbp = new DirectorBuilderPhone();
//建造者
BuilderPhone bp = new BuilderN8();
//建造
dbp.Construct(bp);
//返回產品
bp.GetPhone();
}
優點:
•使用者只需要指定要建造的類型就可以得到它們,而具體的建造過程和細節不需要知道。
•建造代碼與表示相分離,如果要改變一個產品的內部表示,只要再定義一個新的具體的建造者就可以了。
•建造過程由指揮者來控制,建造細節由一個抽象類別來控制,對於實現建造細節的具體類來說,不會遺漏某一個步驟。
缺點:
•產品的構造組件被定義在Builder,增加新的產品的一個細節需要修改Builder,違背了“開閉原則”。
應用情景:
•當建立複雜物件的演算法應該獨立於該對象的組成部分以及它們的裝配方式時。
•當複雜物件的組件相對穩定,不會發生變化時。
PS:
•Builder模式和AbstractFactory模式在功能上很相似,因為都是用來建立大的複雜的對象,它們的區別是:Builder模式強調的是一步步建立對象,並通過相同的建立過程可以獲得不同的結果對象,一般來說Builder模式中對象不是直接返回的。而在AbstractFactory模式中對象是直接返回的,AbstractFactory模式強調的是為建立多個相互依賴的對象提供一個同一的介面。