深入理解Java設計模式之建造者模式
一、什麼是建造者模式
建造者模式也稱生成器模式 定義:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示(依賴倒轉)
產品類:一般是一個較為復雜的對象,也就是說創建對象的過程比較復雜,一般會有比較多的代碼量。在本類圖中,產品類是一個具體的類,而非抽象類。實際編程中,產品類可以是由一個抽象類與它的不同實現組成,也可以是由多個抽象類與他們的實現組成。
抽象建造者:引入抽象建造者的目的,是為瞭將建造的具體過程交與它的子類來實現。這樣更容易擴展。一般至少會有兩個抽象方法,一個用來建造產品,一個是用來返回產品。
建造者:實現抽象類的所有未實現的方法,具體來說一般是兩項任務:組建產品;返回組建好的產品。
指揮類:負責調用適當的建造者來組建產品,指揮類一般不與產品類發生依賴關系,與指揮類直接交互的是建造者類。一般來說,指揮類被用來封裝程序中易變的部分。
二、建造者模式的應用場景
1.創建復雜對象的算法獨立於組成對象的部件
2.同一個創建過程需要有不同的內部表象的產品對象
例子:建房子,不管建什麼房子,它們都離不開地基、柱子、層面和墻體這些組成部分,建築工人就是把這些組成部分一個個建起來,最後連成一體建出一棟棟樓房。
三、建造者模式的優缺點
優點
1.客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。
2.每一個具體建造者都獨立,因此可以方便地替換具體建造者或增加新的具體建造者, 用戶使用不同的具體建造者即可得到不同的產品對象 。
3.可以更加精細地控制產品的創建過程 。將復雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰,也更方便使用程序來控制創建過程。
4.增加新的具體建造者無須修改原有類庫的代碼,指揮者類針對抽象建造者類編程,系統擴展方便,符合“開閉”。
缺點
1.當建造者過多時,會產生很多類,難以維護。
2.建造者模式所創建的產品一般具有較多的共同點,其組成部分相似,若產品之間的差異性很大,則不適合使用該模式,因此其使用范圍受到一定限制。
3.若產品的內部變化復雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。
四、工廠模式和建造者模式的對比
工廠模式用於處理 如何獲取實例對象 問題,建造者模式用於處理如何建造實例對象 問題
建造者模式與工廠模式是極為相似的,總體上,建造者模式僅僅隻比工廠模式多瞭一個“指揮類”的角色。在建造者模式的類圖中,假如把這個指揮類看做是最終調用的客戶端,那麼剩餘的部分就可以看作是一個簡單的工廠模式瞭。
與工廠模式相比,建造者模式一般用來創建更為復雜的對象,因為對象的創建過程更為復雜,因此將對象的創建過程獨立出來組成一個新的類——指揮類。
也就是說,工廠模式是將對象的全部創建過程封裝在工廠類中,由工廠類向客戶端提供最終的產品;而建造者模式中,建造者類一般隻提供產品類中各個組件的建造,而將具體建造過程交付給指揮類。由指揮類負責將各個組件按照特定的規則組建為產品,然後將組建好的產品交付給客戶端。
五、建造者模式的實現
Product
類—產品類,由多個部件組成
//Product類,由多個部件組成 public class Product { List<string> parts = new List<string>(); //添加產品部件 public void Add(string part) { parts.Add(part); } public void show() { Console.WriteLine("\n 創建產品"); foreach (var item in parts) { Console.WriteLine("item"); } } }
Builder
類—抽象建造者類,確定產品由兩個部件PartA和PartB組成,並聲明一個得到產品建造後結果的方法GetResult
abstract class Builder { public abstract void BuilderPartA(); public abstract void BuilderPartB(); public abstract Product GetResult(); }
具體建造者類
//ConcreteBuilder1類---具體建造者類 class ConcreteBuilder1 : Builder { private Product product = new Product(); //建造具體的兩個部件 public override void BuilderPartA() { product.Add("部件A"); } public override void BuilderPartB() { product.Add("部件B"); } public override Product GetResult() { return product; } } //ConcreteBuilder2類---具體建造者類 class ConcreteBuilder2 : Builder { private Product product = new Product(); //建造具體的兩個部件 public override void BuilderPartA() { product.Add("部件X"); } public override void BuilderPartB() { product.Add("部件Y"); } public override Product GetResult() { return product; } }
Director
類—指揮者類
class Director { public void Construct(Builder builder) { //用來指揮建造過程 builder.BuilderPartA(); builder.BuilderPartB(); } }
客戶端代碼—客戶不需知道具體的建造過程
static void Main(string[] args) { Director director = new Director(); Builder b1 = new ConcreteBuilder1(); Builder b2 = new ConcreteBuilder2(); //指揮者用ConcreteBuilder1方法建造產品 director.Construct(b1); Product p1 = b1.GetResult(); p1.show(); //指揮者用ConcreteBuilder2方法建造產品 director.Construct(b2); Product p2 = b2.GetResult(); p2.show(); Console.Read(); }
六、總結
建造者模式的使用場合是當創建復雜對象時,把創建對象成員和裝配方法分離出來,放在建造者類中去實現,用戶使用該復雜對象時,不用理會它的創建和裝配過程,隻關心它的表示形式。
其實完全理解這個模式還是要一番思考的,難以搞懂的是指揮者似乎沒什麼存在的必要,在代碼裡也沒體現它的作用,我們也可以把指揮者的方法放在建造者裡面,但為什麼沒有這樣做呢?我想這可能是考慮到單一責任原則,建造者隻負責創建對象的各個部分,至於各個部分創建的順序、裝配方法它就不管瞭。還有就是當順序要改變時,建造者可以不用改動,改動指揮者就好瞭,指揮者隻有一個,建造者有很多,要改建造者就麻煩瞭。
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!