C#設計模式之五創建者模式(Builder)【創建型】
一、引言
今天我們要講講Builder模式,也就是建造者模式,當然也有叫生成器模式的。在現實生活中,我們經常會遇到一些構成比較復雜的物品,比如:電腦,它就是一個復雜的物品,它主要是由CPU、主板、硬盤、顯卡、機箱等組裝而成的。手機當然也是復雜物品,由主板,各種芯片,RAM 和ROM 攝像頭之類的東西組成。但是無論是電腦還是手機,他們的組裝過程是固定的,就拿手機來說,組裝流水線是固定的,不變的,但是把不同的主板和其他組件組裝在一起就會生產出不同型號的手機。那麽在軟件系統中是不是也會存在這樣的對象呢?答案是肯定的。在軟件系統中我們也會遇到類似的復雜對象,並且這個復雜對象的各個部分按照一定的算法組合在一起,此時該對象的創建工作就可以使用Builder模式了,下面我就來詳細看看這個模式吧。
二、建造者模式的詳細介紹
2.1、動機(Motivate)
在軟件系統中,有時候面臨著“一個復雜對象”的創建工作,其通常由各個部分的子對象用一定的算法構成;由於需求的變化,這個復雜對象的各個部分經常面臨著劇烈的變化,但是將它們組合在一起的算法卻相對穩定。如何應對這種變化?如何提供一種“封裝機制”來隔離出“復雜對象的各個部分”的變化,從而保持系統中的“穩定構建算法”不隨著需求改變而改變?
2.2、意圖(Intent)
將一個復雜對象的構建與其表示相分離,使得同樣的構建過程可以創建不同的表示。
2.3、結果圖
2.4、模式的組成
1. 抽象建造者角色(Builder):為創建一個Product對象的各個部件指定抽象接口,以規範產品對象的各個組成成分的建造。一般而言,此角色規定要實現復雜對象的哪些部分的創建,並不涉及具體的對象部件的創建。
2. 具體建造者(ConcreteBuilder)
1)實現Builder的接口以構造和裝配該產品的各個部件。即實現抽象建造者角色Builder的方法。
2)定義並明確它所創建的表示,即針對不同的商業邏輯,具體化復雜對象的各部分的創建
3) 提供一個檢索產品的接口
4) 構造一個使用Builder接口的對象即在指導者的調用下創建產品實例
3.指導者(Director):調用具體建造者角色以創建產品對象的各個部分。指導者並沒有涉及具體產品類的信息,真正擁有具體產品的信息是具體建造者對象。它只負責保證對象各部分完整創建或按某種順序創建。
4.產品角色(Product):建造中的復雜對象。它要包含那些定義組件的類,包括將這些組件裝配成產品的接口。
2.5 建築者模式的具體實現
現在人們生活水平都提高了,家家都有了家庭轎車,那今天我們就以汽車組裝為例來說明Builder模式的實現。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 7 /// <summary> 8 /// 現在人們的生活水平都提高了,有錢了,我今天就以汽車組裝為例子 9 /// 每臺汽車的組裝過程都是一致的,所以我們使用同樣的構建過程可以創建不同的表示(即可以組裝成不同型號的汽車,不能像例子這樣,一會別克,一會奧迪的) 10 /// 組裝汽車、電腦、手機、電視等等負責對象的這些場景都可以應用建造者模式來設計 11 /// </summary> 12 namespace 設計模式之建造者模式 13 { 14 /// <summary> 15 /// 客戶類 16 /// </summary> 17 class Customer 18 { 19 static void Main(string[] args) 20 { 21 Director director = new Director(); 22 Builder buickCarBuilder = new ConcreteBuilder1(); 23 Builder aoDiCarBuilder = new ConcreteBuilder2(); 24 25 director.Construct(buickCarBuilder); 26 27 //組裝完成,我來駕駛別克了 28 Car buickCar = buickCarBuilder.GetCar(); 29 buickCar.Show(); 30 31 // 我老婆就要奧迪了,她比較喜歡大品牌 32 director.Construct(aoDiCarBuilder); 33 Car aoDiCar = aoDiCarBuilder.GetCar(); 34 aoDiCar.Show(); 35 36 Console.Read(); 37 } 38 } 39 40 /// <summary> 41 /// 這個類型才是組裝的,Construct方法裏面的實現就是創建復雜對象固定算法的實現,該算法是固定的,或者說是相對穩定的 42 /// 這個人當然就是老板了,也就是建造者模式中的指揮者 43 /// </summary> 44 public class Director 45 { 46 // 組裝汽車 47 public void Construct(Builder builder) 48 { 49 builder.BuildCarDoor(); 50 builder.BuildCarWheel(); 51 builder.BuildCarEngine(); 52 } 53 } 54 55 /// <summary> 56 /// 汽車類 57 /// </summary> 58 public class Car 59 { 60 // 汽車部件集合 61 private IList<string> parts = new List<string>(); 62 63 // 把單個部件添加到汽車部件集合中 64 public void Add(string part) 65 { 66 parts.Add(part); 67 } 68 69 public void Show() 70 { 71 Console.WriteLine("汽車開始在組裝......."); 72 foreach (string part in parts) 73 { 74 Console.WriteLine("組件"+part+"已裝好"); 75 } 76 77 Console.WriteLine("汽車組裝好了"); 78 } 79 } 80 81 /// <summary> 82 /// 抽象建造者,它定義了要創建什麽部件和最後創建的結果,但是不是組裝的的類型,切記 83 /// </summary> 84 public abstract class Builder 85 { 86 // 創建車門 87 public abstract void BuildCarDoor(); 88 // 創建車輪 89 public abstract void BuildCarWheel(); 90 //創建車引擎 91 public abstract void BuildCarEngin(); 92 // 當然還有部件,大燈、方向盤等,這裏就省略了 93 94 // 獲得組裝好的汽車 95 public abstract Car GetCar(); 96 } 97 98 /// <summary> 99 /// 具體創建者,具體的車型的創建者,例如:別克 100 /// </summary> 101 public class ConcreteBuilder1 : Builder 102 { 103 Car buickCar = new Car(); 104 public override void BuildCarDoor() 105 { 106 buickCar.Add("Buick‘s Door"); 107 } 108 109 public override void BuildCarWheel() 110 { 111 buickCar.Add("Buick‘s Wheel"); 112 } 113 114 public override void BuildCarEngine() 115 { 116 buickCar.Add("Buick‘s Engine"); 117 } 118 119 public override Car GetCar() 120 { 121 return buickCar; 122 } 123 } 124 125 /// <summary> 126 /// 具體創建者,具體的車型的創建者,例如:奧迪 127 /// </summary> 128 public class ConcreteBuilder2 : Builder 129 { 130 Car aoDiCar = new Car(); 131 public override void BuildCarDoor() 132 { 133 aoDiCar.Add("Aodi‘s Door"); 134 } 135 136 public override void BuildCarWheel() 137 { 138 aoDiCar.Add("Aodi‘s Wheel"); 139 } 140 141 public override void BuildCarEngine() 142 { 143 aoDiCar.Add("Aodi‘s Engine"); 144 } 145 146 public override Car GetCar() 147 { 148 return aoDiCar; 149 } 150 } 151 }
上面代碼中都有詳細的註釋代碼,這裏就不過多解釋。
三、建造者模式的實現要點
在建造者模式中,指揮者是直接與客戶端打交道的,指揮者將客戶端創建產品的請求劃分為對各個部件的建造請求,再將這些請求委派到具體建造者角色,具體建造者角色是完成具體產品的構建工作的,卻不為客戶所知道。 建造者模式主要用於“分步驟來構建一個復雜的對象”,其中“分步驟”是一個固定的組合過程,而復雜對象的各個部分是經常變化的。 產品不需要抽象類,由於建造模式的創建出來的最終產品可能差異很大,所以不大可能提煉出一個抽象產品類。 在前面文章中介紹的抽象工廠模式解決了“系列產品”的需求變化,而建造者模式解決的是 “產品部分” 的需要變化。 由於建造者隱藏了具體產品的組裝過程,所以要改變一個產品的內部表示,只需要再實現一個具體的建造者就可以了,從而能很好地應對產品組成組件的需求變化。
四、.NET 中建造者模式的實現
在微軟的類庫裏面大量使用了設計模式,如果要想學習設計模式,仔細看看微軟的類庫是很有幫助的。今天的設計模式在FCL裏面也有實現,該類型的名字就是System.Text.StringBuilder(存在mscorlib.dll程序集中),它就是一個建造者模式的實現,從名稱也可以看出來。不過它的實現屬於建造者模式的演化,此時的建造者模式沒有指揮者角色和抽象建造者角色,StringBuilder類即扮演著具體建造者的角色,也同時扮演了指揮者和抽象建造者的角色,StringBuilder類扮演著建造string對象的具體建造者角色,其中的ToString()方法用來返回具體產品給客戶端(相當於上面代碼中GetProduct方法)。其中Append方法用來創建產品的組件(相當於上面代碼中BuildPartA和BuildPartB方法),因為string對象中每個組件都是字符,所以也就不需要指揮者的角色的代碼(指的是Construct方法,用來調用創建每個組件的方法來完成整個產品的組裝),因為string字符串對象中每個組件都是一樣的,都是字符,所以Append方法也充當了指揮者Construct方法的作用。
五、總結
今天就到這裏了,還需要重申的是,學習設計模式不能死學,就像StringBuilder一樣,他和Gof23種設計模式中定義的情形有很大的不同,但是它也是Builder模式,因為它們要解決的問題和使用場景是吻合的。我們寫代碼的時候,不要太居於形式,要看使用的契機和模式是否吻合,根據具體的情況我們的模式也會發生變化。當我們看得越多,寫的越多時候,你的變化就越自然了。
今天是2017年9月30日,明天就是國慶了,10月4日又是中秋,我在此祝大家節日快樂,工作順利。我也要休息幾天了,暫時就不寫東西了。
C#設計模式之五創建者模式(Builder)【創建型】