建造者模式將一個複雜的對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。建立者模式隱藏了複雜對象的建立過程,它把複雜對象的建立過程加以抽象,經過子類繼承或者重載的方式,動態的建立具備複合屬性的對象。
雖然與工廠模式、抽象工廠模式、單件模式同爲建立型模式,但建造者模式與以前學習的模式相比,更爲關注建立過程的細節,它通常用於建立複雜對象,從獨立建立每一個部分到最後的組裝,它承擔每一個步驟的工做。因爲它把建立每一個部分都獨立爲一個單一的過程,所以不只能夠完成較爲精細的建立,還能夠根據建立步驟編排,生成不一樣的目標實例。
GOF對建造者模式的描述是:
Separate the construction of a complex object from its representation so that the same construction process can create different representations..
— Design Patterns : Elements of Reusable Object-Oriented Software設計模式
建立者模式很是適用於產品局部加工過程變化較大,但組裝過程相對固定的場景。
好比電腦的組裝,基本的組裝過程是固定的,可是具體主板、CPU、顯卡、內存、硬盤等選擇的品牌和型號可能差別很大;還有汽車的生產也是這樣,總體組裝過程基本相同,但不一樣品牌、價格的汽車在具體部件上差別很大。markdown
其UML類圖以下:
學習
其中包括三個角色:優化
這裏的產品類型並無統一的IProduct接口,主要是由於通過不一樣ConcreteBuilder加工後的產品差異相對較大,給它一個公共的基準抽象對象意義不大,ui
代碼實現:設計
public class House { public void AddWindowAndDoor() { } public void AddWallAndFloor() { } public void AddCeiling() { } } public class Car { public void AddWheel() { } public void AddEngine() { } public void AddBody() { } } public interface IBuilder { void BuildPart1(); void BuildPart2(); void BuildPart3(); } public class CarBuilder : IBuilder { private Car car; public void BuildPart1() { car.AddEngine(); } public void BuildPart2() { car.AddWheel(); } public void BuildPart3() { car.AddBody(); } } public class HouseBuilder : IBuilder { private House house; public void BuildPart1() { house.AddWallAndFloor(); } public void BuildPart2() { house.AddCeiling(); } public void BuildPart3() { house.AddWindowAndDoor(); } } public class Director { public void Construct(IBuilder builder) { builder.BuildPart1(); builder.BuildPart2(); builder.BuildPart3(); } }
調用:3d
[Test] public void BuilderTest() { Director director = new Director(); CarBuilder carBuilder = new CarBuilder(); HouseBuilder houseBuilder = new HouseBuilder(); director.Construct(carBuilder); director.Construct(houseBuilder); Assert.AreEqual(typeof(Car), carBuilder.Car.GetType()); Assert.AreEqual(typeof(House), houseBuilder.House.GetType()); }
並且經典建造者中IBuilder定義了數目固定的裝配動做,而Director有把這些動做的執行順序也固定了,雖然建造者模式能夠生產差別很是大的產品,但要求這些產品具備固定的裝配步驟,這就大大侷限了這種模式的使用場景,由於現實中這樣的要求每每很難知足。不一樣的產品每每具備數目不一樣的裝配動做和次序,若是要把這樣的產品添加到建造者的生產列表中是作不到的,須要另外實現一套,改動比較大。code
上述問題能夠經過對經典模式適當優化來解決。
IBuilder中定義的不一樣步驟能夠進一步抽象爲一個Action,CarBuilder和HouseBuilder的代碼也很類似,能夠提取一個基類,這部分代碼放在基類中。
代碼以下:對象
public interface IBuilder<T> where T : class, new() { T BuildUp(); } public abstract class BuilderBase<T> : IBuilder<T> where T : class, new() { protected IList<Action> steps = new List<Action>(); protected T product = new T(); public virtual T BuildUp() { foreach (Action step in steps) { step(); } return product; } } public class ConcreteCarBuilder : BuilderBase<Car> { public ConcreteCarBuilder() : base() { steps.Add(product.AddEngine); steps.Add(product.AddWheel); steps.Add(product.AddBody); } } public class ConcreteHouseBuilder : BuilderBase<House> { public ConcreteHouseBuilder() : base() { steps.Add(product.AddWallAndFloor); steps.Add(product.AddCeiling); steps.Add(product.AddWindowAndDoor); } }
實體Builder兼作Director,具體的構建步驟由實體Builder來決定,這樣作的好處是很是靈活,不一樣的Builder能夠有不一樣數目的動做,動做的順序也能夠自行安排。blog
調用:
[Test] public void DelegateBuilderTest() { IBuilder<Car> builder = new ConcreteCarBuilder(); var product = builder.BuildUp(); Assert.AreEqual(typeof(Car), product.GetType()); IBuilder<House> builder1 = new ConcreteHouseBuilder(); var product1 = builder1.BuildUp(); Assert.AreEqual(typeof(House), product1.GetType()); }
參考書籍: 王翔著 《設計模式——基於C#的工程化實現及擴展》