Java 設計模式——建造者模式(Builder Pattern)

image

前言

建造者模式又被稱呼為生成器模式,這種類型的設計模式屬于創建型模式,它提供了一種創建對象的最佳方式。
使用多個簡單的對象一步一步構建成一個復雜的對象,有點像造房子一樣一步步從地基做起到萬丈高樓。我想這也是為什么被稱呼為建造者模式的原因吧!反正我是找不出更好的理由了。這樣理解反而更容易記住。不好意思,廢話有點多了,且看下文如何分解!??!

一、簡介

1、定義:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示
2、主要作用:在用戶不知道對象的建造過程和細節的情況下就可以直接創建復雜的對象。
3、如何使用:用戶只需要給出指定復雜對象的類型和內容,建造者模式負責按順序創建復雜對象(把內部的建造過程和細節隱藏起來)
4、解決的問題
(1)、方便用戶創建復雜的對象(不需要知道實現過程)
(2)、代碼復用性 & 封裝性(將對象構建過程和細節進行封裝 & 復用)
5、注意事項:與工廠模式的區別是:建造者模式更加關注與零件裝配的順序,一般用來創建更為復雜的對象

哈哈! 本人比較懶,上面特性都是從其他博客中吸取到的精華,歸納與此,方便以后查閱。

image

二、實現方式

研究了好久發現關于建造者模式的實現例子有好多,有造人、造車、造房子、造世界的...等好多。但歸類后有兩種實現方式。

(1)通過Client、Director、Builder和Product形成的建造者模式

(2)通過靜態內部類方式實現零件無序裝配話構造

三、常見第一種方式

通過Client、Director、Builder和Product形成的建造者模式

(1)一般有以下幾個角色

抽象建造者(builder):描述具體建造者的公共接口,一般用來定義建造細節的方法,并不涉及具體的對象部件的創建。

具體建造者(ConcreteBuilder):描述具體建造者,并實現抽象建造者公共接口。

指揮者(Director):調用具體建造者來創建復雜對象(產品)的各個部分,并按照一定順序(流程)來建造復雜對象。

產品(Product):描述一個由一系列部件組成較為復雜的對象。

(2)舉個例子

既然是建造者模式,那么我們還是繼續造房吧,其實我也想不到更簡單的例子。

假設造房簡化為如下步驟:(1)地基(2)鋼筋工程(3)鋪電線(4)粉刷

“如果”要蓋一座房子,首先要找一個建筑公司或工程承包商(指揮者)。承包商指揮工人(具體建造者)過來造房子(產品),最后驗收。

(3)具體步驟

1、創建抽象建造者定義造房步驟

2、創建工人具體實現造房步驟

3、創建承包商指揮工人施工

4、驗收,檢查是否建造完成

好了,到這里第一種方法就講解完了。具體步驟都給了,大家可以嘗試寫一下,寫不出來沒關系。
——大家可以復制??!省時間嘛,但不寫的話更容易忘記。好了廣告打完了,到貼代碼時間...

image

(4)具體代碼

建造者:Builder.java

/**
 * Builder.java
 *  建造者
 */
abstract class Builder {
    //地基
    abstract void bulidA();
    //鋼筋工程
    abstract void bulidB();
    //鋪電線
    abstract void bulidC();
    //粉刷
    abstract void bulidD();
    //完工-獲取產品
    abstract Product getProduct();
}
image.gif

產品:Product.java

/**
 * Product.java
 *  產品(房子)
 */
public class Product {
    private String buildA;
    private String buildB;
    private String buildC;
    private String buildD;
    public String getBuildA() {
        return buildA;
    }
    public void setBuildA(String buildA) {
        this.buildA = buildA;
    }
    public String getBuildB() {
        return buildB;
    }
    public void setBuildB(String buildB) {
        this.buildB = buildB;
    }
    public String getBuildC() {
        return buildC;
    }
    public void setBuildC(String buildC) {
        this.buildC = buildC;
    }
    public String getBuildD() {
        return buildD;
    }
    public void setBuildD(String buildD) {
        this.buildD = buildD;
    }
    @Override
        public String toString() {
            return buildA+"\n"+buildB+"\n"+buildC+"\n"+buildD+"\n"+"房子驗收完成";
        }
}
image.gif

具體建造者:ConcreteBuilder.java

/**
 * ConcreteBuilder.java
 *  具體建造者(工人)
 */
public class ConcreteBuilder extends Builder{
    private Product product;
    public ConcreteBuilder() {
        product = new Product();
    }
    @Override
    void bulidA() {
        product.setBuildA("地基");
    }
    @Override
    void bulidB() {
        product.setBuildB("鋼筋工程");
    }
    @Override
    void bulidC() {
        product.setBuildC("鋪電線");
    }
    @Override
    void bulidD() {
        product.setBuildD("粉刷");
    }
    @Override
    Product getProduct() {
        return product;
    }
}
image.gif

指揮者:Director.java

/**
 * Director.java
 *  指揮者
 */
public class Director {
    //指揮工人按順序造房
    public Product create(Builder builder) {
        builder.bulidA();
        builder.bulidB();
        builder.bulidC();
        builder.bulidD();
        return builder.getProduct();
    }
}
image.gif

測試類:Test.java

/**
 * Test.java
 *  測試類
 */
public class Test {
    public static void main(String[] args) {
        Director director = new Director();
        Product create = director.create(new ConcreteBuilder());
        System.out.println(create.toString());
    }
}
image.gif
image

代碼貼完了,有沒有感覺,看代碼比看文字好多了。嗯嗯 我也是這么覺得 可惜不能光貼代碼。不然我一天可以寫10篇了T-T。

三、第二種方式

通過靜態內部類方式實現零件無序裝配話構造:案例:Android中的AlertDialog

這種方式使用更加靈活,更符合定義。內部有復雜對象的默認實現,使用時可以根據用戶需求自由定義更改內容,并且無需改變具體的構造方式。就可以生產出不同復雜產品

(1)主要有三個角色:抽象建造者、具體建造者、產品

比第一種方式少了指揮者,主要是因為第二種方式把指揮者交給用戶來操作,使得產品的創建更加簡單靈活。

(2)舉個例子

比如麥當勞的套餐,服務員(具體建造者)可以隨意搭配任意幾種產品(零件)組成一款套餐(產品),然后出售給客戶。

(3)具體步驟

1、創建建造者定義麥當勞的產品

2、創建服務員實現具體產品

3、服務員隨意搭配套餐出售給客戶

(4)具體代碼

建造者:Builder.java

/**
 * Builder.java
 *  建造者
 */
abstract class Builder {
    //漢堡
    abstract Builder bulidA(String mes);
    //飲料
    abstract Builder bulidB(String mes);
    //薯條
    abstract Builder bulidC(String mes);
    //甜品
    abstract Builder bulidD(String mes);
    //獲取套餐
    abstract Product build();
}
image.gif

產品:Product.java

/**
 * Product.java
 *  產品(麥當勞套餐)
 */
public class Product {
    private String buildA="漢堡";
    private String buildB="飲料";
    private String buildC="薯條";
    private String buildD="甜品";
    public String getBuildA() {
        return buildA;
    }
    public void setBuildA(String buildA) {
        this.buildA = buildA;
    }
    public String getBuildB() {
        return buildB;
    }
    public void setBuildB(String buildB) {
        this.buildB = buildB;
    }
    public String getBuildC() {
        return buildC;
    }
    public void setBuildC(String buildC) {
        this.buildC = buildC;
    }
    public String getBuildD() {
        return buildD;
    }
    public void setBuildD(String buildD) {
        this.buildD = buildD;
    }
    @Override
        public String toString() {
            return buildA+"\n"+buildB+"\n"+buildC+"\n"+buildD+"\n"+"組成套餐";
        }
}
image.gif

具體建造者:ConcreteBuilder.java

/**
 * ConcreteBuilder.java
 *  具體建造者(服務員)
 */
public class ConcreteBuilder extends Builder{
    private Product product;
    public ConcreteBuilder() {
        product = new Product();
    }

    @Override
    Product build() {
        return product;
    }

    @Override
    Builder bulidA(String mes) {
        product.setBuildA(mes);
        return this;
    }

    @Override
    Builder bulidB(String mes) {
        product.setBuildB(mes);
        return this;
    }

    @Override
    Builder bulidC(String mes) {
        product.setBuildC(mes);
        return this;
    }

    @Override
    Builder bulidD(String mes) {
        product.setBuildD(mes);
        return this;
    }
}
image.gif

測試類:Test.java

/**
 * Test.java
 *  測試類
 */
public class Test {
    public static void main(String[] args) {
         ConcreteBuilder concreteBuilder = new ConcreteBuilder();
         Product build = concreteBuilder
                .bulidA("牛肉煲")
//              .bulidC("全家桶")
                .bulidD("冰淇淋")
                .build();
        System.out.println(build.toString());
    }
}
image.gif
image

突然發現貼代碼也是一個技術活,一不小心就貼了一晚上。唉唉唉,又熬夜了啊,我可憐的頭發

image

四、總結

(1)優點

1、產品的建造和表示分離,實現了解耦。

2、將復雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰

3、增加新的具體建造者無需修改原有類庫的代碼,易于拓展,符合“開閉原則“。

(2)缺點

1、產品必須有共同點,限制了使用范圍。

2、如內部變化復雜,會有很多的建造類,難以維護。

(3)應用場景

1、需要生成的產品對象有復雜的內部結構,這些產品對象具備共性;

2、隔離復雜對象的創建和使用,并使得相同的創建過程可以創建不同的產品。

3、需要生成的對象內部屬性本身相互依賴。

4、適合于一個具有較多的零件(屬性)的產品(對象)的創建過程。

五、Demo地址

https://github.com/DayorNight/DesignPattern

六、參考文檔

http://www.lxweimin.com/p/be290ccea05a

http://www.runoob.com/design-pattern/builder-pattern.html

https://www.cnblogs.com/lwbqqyumidi/p/3742562.html

七、內容推薦

簡書:https://blog.csdn.net/cs_lwb/article/details/84261641

相關文章:

《JAVA 設計模式——單例模式》

《Java 設計模式——工廠模式》

《Java 設計模式——觀察者模式》

如果你覺得我寫的不錯或者對您有所幫助的話。不妨頂一個(點個贊唄),也方便以后復習

您的每個舉動都是對我莫大的支持

image
image
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容