基礎介紹:
將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。
說白了就是將一個複雜的物件拆分成一個一個零件,然後按照既定順序和規則進行組裝,最終形成這個相對複雜的物件。
具體可分為4個角色:
Product(產品):複雜物件本身。
Builder(抽象建造者):既可以是抽象類也可以是介面,主要是為了約束和規範具體建造者有哪些零件,並提供一個方法返回組裝後的複雜物件。
ConcreteBuilder(具體建造者):它繼承自Builder(抽象建造者),主要是具體實現父類中的那些零件。也就是說在這個類裡就要實際去建立各個零件的具體功能了。
Director(指揮者):又稱為導演類,在指揮者中不涉及具體產品的資訊,只負責保證物件各部分完整建立或按某種順序建立。客戶端一般只需要與指揮者進行互動,在客戶端確定具體建造者的型別,並例項化具體建造者物件,然後透過指揮者類的建構函式或者Setter方法將該物件傳入指揮者類中。
- 特性和功能:將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。
- 使用環境:當建立複雜物件的演算法應該獨立於該物件的組成部分以及它們的裝配方式時。
- 注意事項:建造者模式的使用需要考慮其複雜性,如果產品結構較簡單,使用此模式可能會增加系統的複雜性。
- 優點:客戶端不必知道產品內部組成的細節,將產品本身與產品的建立過程解耦。
- 缺點:產品的組成部分必須相同,限制了其使用範圍。
應用場景:
有時需要建立一個複雜物件,其通常由其各部分子物件透過一定的步驟組合而成。
由於需求的變化,這個複雜物件的各個部分經常面臨著劇烈的變化,但是將它們組合在一起的演算法卻相對穩定。
本質就是:建立的物件較複雜,由多個部件構成,各部件面臨著複雜的變化,但構件間的建造順序是穩定的。
使得相同的建立過程可以建立不同的產品。
造者模式所建立的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式。
- 垃圾食品套餐系統:漢堡、可樂、薯條、炸雞翅等是不變的,而其組合是經常變化的,生成出各種特惠"套餐"。
- 裝修系統:改水電、再貼瓷磚、家電、電視牆等,順序基本不變,用材不同最終生成的產品則不同。
- ......
建立方式:
本例項主要是中Computer是產品,包含CPU、主機板、記憶體、硬碟、顯示卡、機箱等元件。
Builder是抽象建造者,HighPerformanceBuilder和CostEffectiveBuilder是具體的建造者,Director是指揮者。
-
首先要確定產品類
1 /// <summary> 2 /// 產品類 3 /// </summary> 4 public class Computer 5 { 6 public string CPU { get; set; } 7 public string Memory { get; set; } 8 public string Disk { get; set; } 9 }
-
其次是抽象建造者類
1 /// <summary> 2 /// 抽象建造者類 3 /// </summary> 4 public abstract class BuilderComputer 5 { 6 //產品物件---protected關鍵字受保護成員可以在其所在的類、其子類以及同一個名稱空間中的其他類中被訪問。 7 protected Computer computer = new Computer(); 8 9 //以下方法約束了產品由哪些零件組成 10 public abstract void BuildCPU(); 11 public abstract void BuildMemory(); 12 public abstract void BuildDisk(); 13 14 /// <summary> 15 /// 返回物件本身 16 /// </summary> 17 /// <returns></returns> 18 public Computer GetComputer() 19 { 20 return computer; 21 } 22 }
該類中限定了產品的組成部分也就是各個零件。
這裡指明瞭產品由三個零件組成,分別是CPU、Disk和Memory。
-
再者是具體建造者類
1 /// <summary> 2 /// 低配電腦 具體的建立者 3 /// </summary> 4 class LowComputer : BuilderComputer 5 { 6 public override void BuildCPU() 7 { 8 computer.CPU = "i5處理器"; 9 } 10 11 public override void BuildDisk() 12 { 13 computer.Disk = "512G固態"; 14 } 15 public override void BuildMemory() 16 { 17 computer.Memory = "16G記憶體"; 18 } 19 } 20 21 /// <summary> 22 /// 高配電腦 具體的建立者 23 /// </summary> 24 class GoodComputer : BuilderComputer 25 { 26 public override void BuildCPU() 27 { 28 computer.CPU = "i7處理器"; 29 } 30 31 public override void BuildDisk() 32 { 33 computer.Disk = "1T固態"; 34 } 35 public override void BuildMemory() 36 { 37 computer.Memory = "32G記憶體"; 38 } 39 }
上述程式碼中定義了兩個具體建造者,分別是低配電腦和高配電腦。
繼承自抽象建造者類,並具體實現了其中的零件。
如果還有還想新增其他配置點電腦,就可以新增一個具體建造者類,而無需修改其他程式碼。
-
最後是指揮者
1 /// <summary> 2 /// 指揮者-監工 建立物件的順序 3 /// </summary> 4 public class Director 5 { 6 private BuilderComputer _builder = null; 7 8 /// <summary> 9 /// 透過建構函式傳遞具體創造者 10 /// </summary> 11 /// <param name="builder"></param> 12 public Director(BuilderComputer builder) 13 { 14 this._builder = builder; 15 } 16 17 /// <summary> 18 /// 組裝方法,並返回產品 19 /// </summary> 20 /// <returns></returns> 21 public Computer AssembleComputer() 22 { 23 _builder.BuildCPU(); 24 _builder.BuildDisk(); 25 _builder.BuildMemory(); 26 return _builder.GetComputer(); 27 } 28 }
在上述程式碼中是透過建構函式傳遞具體創造者,也可以在AssembleComputer方法中傳遞。
產品的具體組裝規則則是由AssembleComputer方法來完成,如果有多種組裝方式,也可以有多個方法來分別完成。
該類本質就是統籌安排,並直接與客戶端進行互動。
- 客戶端呼叫
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.WriteLine("我想組裝一臺低配電腦:"); 6 //首先例項化一個低配電腦的具體建造物件 7 BuilderComputer builderComputer = new LowComputer(); 8 //然後使用指揮者類來具體組裝這個產品 9 Computer director = new Director(builderComputer).AssembleComputer(); 10 Console.WriteLine("組裝完畢,具體配置如下:"); 11 Console.WriteLine(director.CPU); 12 Console.WriteLine(director.Memory); 13 Console.WriteLine(director.Disk); 14 15 16 Console.WriteLine("\n我又想組裝一臺高配電腦:"); 17 //首先例項化一個高配電腦的具體建造物件 18 builderComputer = new GoodComputer(); 19 //然後使用指揮者類來具體組裝這個產品 20 director = new Director(builderComputer).AssembleComputer(); 21 Console.WriteLine("組裝完畢,具體配置如下:"); 22 Console.WriteLine(director.CPU); 23 Console.WriteLine(director.Memory); 24 Console.WriteLine(director.Disk); 25 26 } 27 }
- 指揮者類也可以省略,組裝交給抽獎建造者來完成
1 /// <summary> 2 /// 抽象建造者類 3 /// </summary> 4 public abstract class BuilderComputer 5 { 6 //產品物件---protected關鍵字受保護成員可以在其所在的類、其子類以及同一個名稱空間中的其他類中被訪問。 7 protected Computer computer = new Computer(); 8 9 //以下方法約束了產品由哪些零件組成 10 public abstract void BuildCPU(); 11 public abstract void BuildMemory(); 12 public abstract void BuildDisk(); 13 14 /// <summary> 15 /// 可以省略掉指揮者類,由此方法進行組裝 16 /// </summary> 17 /// <returns></returns> 18 public Computer Construct() 19 { 20 this.BuildCPU(); 21 this.BuildMemory(); 22 this.BuildDisk(); 23 return computer; 24 } 25 }
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.WriteLine("我想組裝一臺低配電腦:"); 6 Computer director = new LowComputer().Construct(); 7 Console.WriteLine("組裝完畢,具體配置如下:"); 8 Console.WriteLine(director.CPU); 9 Console.WriteLine(director.Memory); 10 Console.WriteLine(director.Disk); 11 12 13 Console.WriteLine("\n我又想組裝一臺高配電腦:"); 14 director = new GoodComputer().Construct(); 15 Console.WriteLine("組裝完畢,具體配置如下:"); 16 Console.WriteLine(director.CPU); 17 Console.WriteLine(director.Memory); 18 Console.WriteLine(director.Disk); 19 20 } 21 }
在上述程式碼中可以看出,此處還可以定義了一個虛方法,
在具體建造者中,可以根據需要重寫該方法,使其返回實際需要的值,然後在構建過程中,使用該值進行構建。相較於指揮者類,具體產品的組裝可以交由產品本身去組裝。
總結:
建造者模式所建立的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,並不適合使用建造者模式。
建造者隱藏了具體產品的組裝過程,所以要改變一個產品的內部表示,只需要再實現一個具體的建造者就可以了,從而能很好地應對產品組成元件的需求變化。
需要生產的產品物件有複雜的內部結構,這些產品物件通常包含多個成員變數,產品物件的屬性相互依賴,需要指定其生成順序。
物件的建立過程獨立於建立該物件的類,隔離複雜物件的建立和使用,並使得相同的建立過程可以建立不同的產品。
附:建立者模式對比
工廠模式解決了“同一類產品”的需求變化,抽象工廠模式解決了“系列產品”的需求變化,而建造者模式解決的是 “產品部分” 的需要變化。
工廠方法模式 VS 建造者模式
工廠方法模式側重整體物件的建立方式,建造者模式側重零部件的構建,然後透過一定順序和規則構造出一個複雜的物件。
例如:想要製作一個假人,如果使用工廠方法模式,直接生產出來一個XX材質、XX高、XX重的假人人就可以了。
而如果使用建造者模式,則需要先建立出四肢、頭和軀幹等部位,然後按照一定順序進行組裝形成一個完整的假人。
抽象工廠模式 VS 建造者模式
抽象工廠模式側重對產品族(系列產品)的建立,一個產品族是這樣的一系列產品。
採用抽象工廠模式不需要關心構建過程,只關心什麼產品由什麼工廠生產即可。
建造者模式則側重要求按照指定的藍圖建造產品,它的主要目的是透過組裝零配件而產生一個新產品。
如果將抽象工廠模式看成汽車配件生產工廠,生產一個產品族的產品,那麼建造者模式就是一個汽車組裝工廠,透過對部件的組裝可以返回一輛完整的汽車。