1. 程式人生 > 實用技巧 >設計模式——建造者模式

設計模式——建造者模式

建造者模式(Builder Pattern:使用簡單的物件一步一步構建成一個複雜的物件。這種設計模式屬於建立者模式,它提供了一種建立物件的最佳方式。一個 Builder 類會一步一步構造最終的物件。該 Builder 類是獨立於其他物件的。例如,計算機是由 CPU、主機板、記憶體、硬碟、顯示卡、機箱、顯示器、鍵盤、滑鼠等部件組裝而成的,採購員不可能自己去組裝計算機,而是將計算機的配置要求告訴計算機銷售公司,計算機銷售公司安排技術人員去組裝計算機,然後再交給要買計算機的採購員。

以上所有這些產品都是由多個部件構成的,各個部件可以靈活選擇,但其建立步驟都大同小異。這類產品的建立無法用前面介紹的工廠模式描述,只有建造者模式可以很好地描述該類產品的建立。

一、基本介紹


1)、建造者模式:又叫生成器模式,是一種物件構建模式。它可以將複雜物件的建造過程抽象出來(抽象類別),使這個抽象過程的不同實現方法可以構造出不同表現(屬性)的物件。
2)、構造者模式,它允許使用者只通過指定複雜物件的型別和內容就可以構建它們,使用者不需要知道內部的具體構建細節。
3)、構造者模式主要解決在軟體系統中,當面臨一個複雜物件的建立工作時,其通常由各個部分的子物件用一定的演算法構成;由於需求的變化,這個複雜物件的各個部分經常面臨劇烈的變化,但是將它們組合在一起的演算法卻相對穩定。
4)、主要適用於:一些基本部件不會變,而其組合經常變化的情況。主要是將變與不變進行分離(去肯德基,漢堡、可樂、薯條、炸雞翅等是不變的,而其組合是經常變化的,生成出所謂的"套餐")。

二、建造者模式的四個角色


1)、Product(產品角色):包含多個組成部件的複雜物件(產品物件)。
2)、Builder(抽象建造者):建立一個包含 Product 各個子部件的抽象方法或介面,通常還包含了一個返回複雜產品的方法。
3)、ConcreteBuilder(具體建造者):實現 Builder 介面,構建和裝備各個子部件的具體實現。
4)、Director(指揮者):構建一個使用 Builder 介面的物件。它主要作用是用於建立一個複雜的物件。在指揮者中不涉及具體產品的資訊。主要分兩個作用,一是隔離客戶與物件的生產過程,二是負責控制物件的生產過程。

三、建造者模式的注意事項和細節


1)、客戶端不必知道產品內部組成的細節,將產品本身與產品的建立過程解耦,使得相同的建立過程可以建立不同的產品物件。
2)、每一個具體建造者都相對獨立,因此可以方便的替換或者新增具體建造者,使用者使用不同的具體建造者即可得到不同的產品物件。
3)、可以更加精準的控制產品的建立過程。將複雜產品的建立步驟分解在不同的方法中,使得建立過程更加清晰,也更方便使用程式來控制建立過程。
4)、增加新的具體建築者無需修改原有類庫程式碼,指揮者類針對抽象建造者類程式設計,系統擴充套件方便。符合 OCP 原則。
5)、建造者模式建立的產品具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合建造者模式,因此其使用範圍受到一定的限制。
6)、如果產品的內部變化複雜,可能會導致需要定義很多具體建造者內來實現這種變化,導致系統變得龐大,因此這種情況下,考慮是否選擇建造者模式。
7)、抽象工廠模式 VS 建造者模式:抽象工廠模式實現對產品家族的建立,一個產品家族就是一系列產品。具有不同分類維度的產品組合,採用抽象工廠模式不需要關係構建過程,只關係產品由什麼工廠生成即可。而建造者模式則是要求按照指定的藍圖建造產品,它主要目的是通過組裝零配件而產生一個新產品。

四、建造者模式原理類圖:可以參考五中的程式碼一起觀看


五、建造者模式案例


【1】建立 Product 產品角色:

1 public class Product {
2     private String CPU;
3     //主機板 mainboard
4     private String mainboard;
5     //記憶體 memory
6     private String memory;
7     //.....略
8     //生成get set 方法 略
9 }

【2】抽象建造者物件:

 1 public abstract class Builder {
 2     //組合 產品物件
 3     protected Product product = new Product();
 4     
 5     //抽象方法
 6     public abstract void buildCpu();
 7     public abstract void buildMainboard();
 8     public abstract void buildMemory();
 9     
10     //返回一個產品物件
11     public Product getResult() {
12         return product;
13     }
14 }

【3】具體建造者物件:一般會有多個這種物件,都實現 Builder 抽象類。

 1 public class ConcreteBuilder_huawei extends Builder{
 2 
 3     @Override
 4     public void buildCpu() {
 5         product.setCPU("華為CPU");
 6     }
 7 
 8     @Override
 9     public void buildMainboard() {
10         product.setMainboard("華為主機板");
11     }
12 
13     @Override
14     public void buildMemory() {
15         product.setMemory("華為記憶體");
16     }
17     
18 }

【4】指揮者類,主要構建組裝的流程:返回的是產品物件

 1 public class Director {
 2     //需要將抽象類聚合進來
 3     Builder builder = null;
 4     //建立一個構造器 呼叫時傳入具體的實現類
 5     public Director(Builder builder) {
 6         this.builder = builder;
 7     }
 8     //新增set 方法 使用者可以通過此方法修改已有的 建造者物件
 9     public void setBuilder(Builder builder) {
10         this.builder = builder;
11     }
12     
13     //筆記本的組成流程  返回的是產品類
14     public Product pack_pc() {
15         builder.buildMainboard();
16         builder.buildCpu();
17         builder.buildMemory();
18         return builder.getResult();
19     }
20 }

【5】客戶端通過指揮者類呼叫需要的品牌電腦:

 1 public class Client {
 2     public static void main(String[] args) {
 3         //建立需要的電腦子部件——例如我們要組裝的是 華為
 4         ConcreteBuilder_huawei huawei = new ConcreteBuilder_huawei();
 5         //呼叫指揮者類,將需要的品牌傳入,根據控制著中的流程進行組裝
 6         Director director = new Director(huawei);
 7         //呼叫組裝方法,返回產品
 8         Product pack_pc = director.pack_pc();
 9         //檢視輸入的結果 
10         System.out.println(pack_pc.toString());
11         //結果為:Product [CPU=華為CPU, mainboard=華為主機板, memory=華為記憶體]
12     }
13 }

六、原始碼分析(StringBuilder)


【1】java.lang.StringBuilder 中的建造者模式:

1 public class OrginBuilder {
2     public static void main(String[] args) {
3         StringBuilder builder = new StringBuilder("hello");
4         builder.append("world");
5     }
6 }

【2】進入 append 方法,會發現 StringBuilder 類即就是我們所說的指揮者。建造方法的具體實現是由 AbstractStringBuilder 實現。

1     @Override
2     public StringBuilder append(String str) {
3         super.append(str);
4         return this;
5     }

【3】進入 AbstractStringBuilder 類,實現了 Appendable 介面方法,此類已是建造者,只是不能例項化。

1 public AbstractStringBuilder append(String str) {
2     if (str == null)
3         return appendNull();
4     int len = str.length();
5     ensureCapacityInternal(count + len);
6     str.getChars(0, len, value, count);
7     count += len;
8     return this;
9 }

【4】Appendable 介面定義了多個 append 方法(抽象方法),既 Appendle 為抽象建造者,定義了抽象方法。

1 public interface Appendable {
2 
3     Appendable append(CharSequence csq) throws IOException;  
4     ......
5 }