本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7614630.html,記錄一下學習程序以備后續查用,
一、引言
在現實生活中,我們經常會遇到一些構成比較復雜的物品,比如電腦,是由CPU、主板、記憶體條、硬碟、顯卡、機箱等組裝而成的,手機也是復雜物品,
由主板、各種芯片、RAM、ROM、攝像頭等部件組成,但是無論是電腦還是手機,它們的組裝程序是固定的,拿手機來說,組裝流水線是固定的、不變的,
但是把不同的主板和其它組件組裝在一起就會生產出不同型號的手機,那么在軟體系統中是不是也會存在這樣的物件呢?答案是肯定的,在軟體系統中我們
也會遇到類似的復雜物件,并且這個復雜物件的各個部分按照一定的演算法組合在一起,此時該物件的創建作業就可以使用Builder模式了,下面讓我們詳細看
看這個模式吧,
二、建造者模式介紹
建造者模式(也叫生成器模式):英文名稱--Builder Pattern;分類--創建型,
2.1、動機(Motivate)
在軟體系統中,有時候面臨著“一個復雜物件”的創建作業,其通常由各個部分的子物件用一定的演算法構成,由于需求的變化,這個復雜物件的各個部分經
常面臨著劇烈的變化,但是將它們組合在一起的演算法卻相對穩定,如何應對這種變化?如何提供一種“封裝機制”來隔離出“復雜物件的各個部分”的變化,從
而保持系統中的“穩定構建演算法”不隨著需求改變而改變?
2.2、意圖(Intent)
將一個復雜物件的構建與其表示相分離,使得同樣的構建程序可以創建不同的表示,——《設計模式》GoF
2.3、結構圖(Structure)

2.4、模式的組成
1)抽象建造者角色(Builder):為創建一個Product物件的各個部件指定抽象介面,以規范產品物件的各個組成部分的建造,一般而言,此角色規定要實
現復雜物件的哪些部件的創建,并不涉及具體的物件部件的創建,
2)具體建造者(ConcreteBuilder)
I、實作Builder的介面以構造和裝配該產品的各個部件,即實作抽象建造者角色Builder的方法,
II、定義并明確它所創建的表示,即針對不同的商業邏輯,具體化復雜物件的各個部分的創建,
III、提供一個檢索產品的介面,
IV、構造一個使用Builder介面的物件,即在指導者的呼叫下創建產品實體,
3)指導者(Director):呼叫具體建造者角色以創建產品物件的各個部分,指導者并沒有涉及具體產品類的資訊,真正擁有具體產品的資訊是具體建造者
物件,它只負責保證物件各部分完整創建或按某種順序創建,
4)產品角色(Product):建造中的復雜物件,它要包含那些定義組件的類,包括將這些組件裝配成產品的介面,
2.5、建造者模式的具體實作
現在人們生活水平都提高了,家家都有了家庭轎車,那今天我們就以汽車組裝為例來說明Builder模式的實作,
class Program { /// <summary> /// 小轎車類 /// </summary> public sealed class SaloonCar { //小轎車部件集合 private IList<string> parts = new List<string>(); //把單個部件添加到小轎車部件集合中 public void Add(string part) { parts.Add(part); } public void Show() { Console.WriteLine("小轎車開始組裝......."); foreach (string part in parts) { Console.WriteLine("部件[" + part + "]已組裝,"); } Console.WriteLine("小轎車組裝完畢,"); } } /// <summary> /// 抽象建造者,它定義了要創建什么部件和最后創建的結果,但是不是組裝的的型別,切記, /// </summary> public abstract class Builder { //創建車門 public abstract void BuildSaloonCarDoor(); //創建車輪 public abstract void BuildSaloonCarWheel(); //創建車引擎 public abstract void BuildSaloonCarEngine(); //獲得組裝好的小轎車 public abstract SaloonCar GetSaloonCar(); } /// <summary> /// 具體創建者,具體車型的創建者,例如:別克, /// </summary> public sealed class BuickBuilder : Builder { SaloonCar buickCar = new SaloonCar(); public override void BuildSaloonCarDoor() { buickCar.Add("Buick's door"); } public override void BuildSaloonCarWheel() { buickCar.Add("Buick's wheel"); } public override void BuildSaloonCarEngine() { buickCar.Add("Buick's engine"); } public override SaloonCar GetSaloonCar() { return buickCar; } } /// <summary> /// 具體創建者,具體車型的創建者,例如:奧迪 /// </summary> public sealed class AoDiBuilder : Builder { SaloonCar aoDiCar = new SaloonCar(); public override void BuildSaloonCarDoor() { aoDiCar.Add("Aodi's door"); } public override void BuildSaloonCarWheel() { aoDiCar.Add("Aodi's wheel"); } public override void BuildSaloonCarEngine() { aoDiCar.Add("Aodi's engine"); } public override SaloonCar GetSaloonCar() { return aoDiCar; } } /// <summary> /// 這個型別才是組裝的 /// Construct方法里面的實作就是創建復雜物件固定演算法的實作,該演算法是固定的或者說是相對穩定的, /// 這個人當然就是老板了,也就是建造者模式中的指揮者, /// </summary> public class Director { //組裝汽車 public void Construct(Builder builder) { builder.BuildSaloonCarDoor(); builder.BuildSaloonCarWheel(); builder.BuildSaloonCarEngine(); } } static void Main(string[] args) { #region 建造者模式 Director director = new Director(); Builder buickBuilder = new BuickBuilder(); Builder aoDiBuilder = new AoDiBuilder(); //組裝別克小轎車 director.Construct(buickBuilder); SaloonCar buickCar = buickBuilder.GetSaloonCar(); buickCar.Show(); Console.WriteLine(); //組裝奧迪小轎車 director.Construct(aoDiBuilder); SaloonCar aoDiCar = aoDiBuilder.GetSaloonCar(); aoDiCar.Show(); Console.Read(); #endregion } }View Code
運行結果如下:

三、建造者模式的實作要點
在建造者模式中,指揮者是直接與客戶端打交道的,指揮者將客戶端創建產品的請求轉換為對各個部件的建造請求,再將這些請求委派給具體的建造者角
色,而具體的建造者角色是完成具體產品的構建作業的,卻不為客戶所知道,
建造者模式主要用于“分步驟來構建一個復雜的物件”,其中“分步驟”是一個固定的組合程序,而復雜物件的各個部分是經常變化的, 產品不需要抽象類,
因為建造者模式創建出來的最終產品可能差異很大,所以不大可能提煉出一個抽象產品類, 在前面文章中介紹的抽象工廠模式解決了“多系列產品”的需求變
化,而建造者模式解決的是 “產品部分” 的需要變化, 由于建造者隱藏了具體產品的組裝程序,所以要改變一個產品的內部表示,只需要再實作一個具體的
建造者就可以了,從而能很好地應對產品組成部件的需求變化,
3.1、建造者模式的優點
1)使用建造者模式可以使客戶端不必知道產品內部組成的細節,
2)具體的建造者類之間是相互獨立的,容易擴展,
3)由于具體的建造者是獨立的,因此可以對建造程序逐步細化,而不對其他的模塊產生任何影響,
3.2、建造者模式的缺點
1)產生多余的Build物件以及Dirextor類,
3.3、創建者模式的使用場合
1)當創建復雜物件的演算法應該獨立于該物件的組成部分以及它們的裝配方式時,
2)相同的方法,不同的執行順序,產生不同的事件結果時,
3)多個部件或零件,都可以裝配到一個物件中,但是產生的運行結果又不相同時,
4)產品類非常復雜,或者產品類中的呼叫順序不同產生了不同的效能,
5)創建一些復雜的物件時,這些物件的內部組成構件間的建造順序是穩定的,但是物件的內部組成構件面臨著復雜的變化,
四、.NET中建造者模式的實作
微軟的類別庫里面大量使用了設計模式,如果要想學習設計模式,仔細看看微軟的類別庫是很有幫助的,今天的設計模式在FCL里面也有實作,該型別的名字
是System.Text.StringBuilder(存在于mscorlib.dll程式集中),它就是一個建造者模式的實作,從名稱也可以看出來,不過它的實作屬于建造者模式的演化,此時
的建造者模式沒有指揮者角色和抽象建造者角色,StringBuilder類既扮演著具體建造者的角色,也同時扮演了指揮者和抽象建造者的角色,
StringBuilder類扮演著建造string物件的具體建造者角色,其中的ToString()方法用來回傳具體產品給客戶端(相當于上面代碼中GetSaloonCar方法),其中
Append方法用來創建產品的組件(相當于上面代碼中Add方法),因為string物件中每個組件都是字符,所以也就不需要指揮者角色的代碼(如上面代碼中的
Construct方法),Append方法也充當了指揮者Construct方法的作用,
五、總結
需要重申的是,學習設計模式不能死學,就像StringBuilder一樣,他和Gof23種設計模式中定義的情形有很大的不同,但是它也是Builder模式,因為它要解決
的問題和使用場景是吻合的,我們寫代碼的時候,不要太居于形式,要看使用的貧訓和模式是否吻合,根據具體的情況我們的模式也會發生變化,當我們看得越
多也寫得越多的時候,變化就越自然了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/57151.html
標籤:其他
