設計模式(六)建造者模式

版權聲明:轉載必須註明本文轉自曉_晨的博客:http://blog.csdn.net/niunai112

目錄

導航

設計模式之六大設計原則
設計模式(一)單例模式
設計模式(二)工廠模式
設計模式(三)策略模式
設計模式(四)適配器模式
設計模式(五)享元模式
設計模式(六)建造者模式
設計模式(七)原型模式
設計模式(八)橋接模式
設計模式(九)外觀模式
設計模式(十)組合模式
設計模式(十一)裝飾器模式
設計模式(十二)代理模式
設計模式(十三)迭代器模式
設計模式(十四)觀察者模式
設計模式(十五)中介者模式
設計模式(十六)命令模式
設計模式(十七)狀態模式
設計模式(十八)訪問者模式
設計模式(十九)責任鏈模式
設計模式(二十)解釋器模式
設計模式(二十一)備忘錄模式
設計模式(二十二)模板模式
設計模式總結篇(爲什麼要學習設計模式,學習設計模式的好處)

前言

在開發過程,有的時候會出現一個複雜對象的創建工作,這個對象一般組裝模式固定,但是其中的參數會變,比如像電腦,汽車等,可拆分的東西,基本都能使用這個模式,只是看有沒有必要,一些本來就是固定死的東西,用工廠模式或者享元模式會更好。

例子

假如你是一家雲提供商,你的客戶需要不同種類的產品,你要給不同客戶提供產品。

/***
 *
 *@Author ChenjunWang
 *@Description:產品類,服務器有操作系統,所用語言,所選服務器和所選數據庫
 *@Date: Created in 21:05 2018/3/20
 *@Modified By:
 *
 */

public class ServerProduct {
    String os;
    String language;
    String server;
    String database;

    public String getOs() {
        return os;
    }

    public void setOs(String os) {
        this.os = os;
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public String getServer() {
        return server;
    }

    public void setServer(String server) {
        this.server = server;
    }

    public String getDatabase() {
        return database;
    }

    public void setDatabase(String database) {
        this.database = database;
    }

    public String getEnvironment() {
        return "ServerProduct{" +
                "os='" + os + '\'' +
                ", language='" + language + '\'' +
                ", server='" + server + '\'' +
                ", database='" + database + '\'' +
                '}';
    }
}

假設有個客戶選了經典套餐

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 21:19 2018/3/20
 *@Modified By:
 *
 */
public class Customer {
    public static void main(String[] args) {
        ServerProduct customer = new ServerProduct();
        customer.setOs("Ubuntu");
        customer.setLanguage("Java");;
        customer.setDatabase("Mysql");
        customer.setServer("Tomcat");
        System.out.println("客戶1要的環境:" + customer.getEnvironment());
    }
}
運行結果如下
-------------------------------
客戶1要的環境:ServerProduct{os='Ubuntu', language='Java', server='Tomcat', database='Mysql'}

沒問題,環境出來了,客戶很滿意,後來又有一個客戶說系統要centos,然後我們又要把全部流程走一遍

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 21:19 2018/3/20
 *@Modified By:
 *
 */
public class Customer {
    public static void main(String[] args) {
        ServerProduct customer = new ServerProduct();
        customer.setOs("Ubuntu");
        customer.setLanguage("Java");;
        customer.setDatabase("Mysql");
        customer.setServer("Tomcat");
        System.out.println("客戶1要的環境:" + customer.getEnvironment());

        ServerProduct customer2 = new ServerProduct();
        customer2.setOs("Ubuntu");
        customer2.setLanguage("Java");;
        customer2.setDatabase("Mysql");
        customer2.setServer("Tomcat");
        System.out.println("客戶2要的環境:" + customer2.getEnvironment());

    }
}
運行結果如下
-------------------------------
客戶1要的環境:ServerProduct{os='Ubuntu', language='Java', server='Tomcat', database='Mysql'}
客戶2要的環境:ServerProduct{os='CentOS', language='Java', server='Tomcat', database='Mysql'}

這樣每次創建一個環境都需要寫大量的重複代碼,所以LZ

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 21:12 2018/3/20
 *@Modified By:
 *
 */
public interface Builder {
    Builder installOS(String OS);
    Builder installLanguage(String language);
    Builder installServer(String server);
    Builder installDatabase(String database);
    ServerProduct getProduct();
}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 22:04 2018/3/20
 *@Modified By:
 *
 */
public class Classic implements Builder{

    private ServerProduct serverProduct = new ServerProduct();
    @Override
    public Builder installOS(String OS) {
        serverProduct.os = OS;
        return this;
    }


    @Override
    public Builder installLanguage(String language) {
        serverProduct.language = language;
        return this;
    }

    @Override
    public Builder installServer(String server) {
        serverProduct.server = server;
        return this;
    }

    @Override
    public Builder installDatabase(String database) {
        serverProduct.database = database;
        return this;
    }

    @Override
    public ServerProduct getProduct() {
        return serverProduct;
    }
}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 22:11 2018/3/20
 *@Modified By:
 *
 */
public class Director {
    private Builder builder = new Classic();
    public ServerProduct createClassicUbuntuEnvironment(){
        builder.installOS("Ubuntu").installLanguage("Java").installServer("Tomcat").installDatabase("Mysql");
        return builder.getProduct();
    }
    public ServerProduct createClassicCentOSEnvironment(){
        builder.installOS("CentOS").installLanguage("Java").installServer("Tomcat").installDatabase("Mysql");
        return builder.getProduct();
    }
}


public class Customer {
    public static void main(String[] args) {
        Director director = new Director();
        ServerProduct classicCentOSEnvironment1 = director.createClassicCentOSEnvironment();
        System.out.println("創建第一個環境:" + classicCentOSEnvironment1.getEnvironment());
        ServerProduct classicCentOSEnvironment2 = director.createClassicUbuntuEnvironment();
        System.out.println("創建第二個環境:" + classicCentOSEnvironment2.getEnvironment());



    }
}
運行結果如下
--------------------------
創建第一個環境:ServerProduct{os='CentOS', language='Java', server='Tomcat', database='Mysql'}
創建第二個環境:ServerProduct{os='Ubuntu', language='Java', server='Tomcat', database='Mysql'}

UML圖
builder
其實,建造者模式到這就結束了,但是LZ還是要拓展一下,這裏存在一個大問題,就是假如使用上面的方法的話,director 再次調用create方法的話,之前的信息就會被替換掉,因爲他們引用的是同一個對象。所以Main應該要按下面這樣寫纔對。

public class Customer {
    public static void main(String[] args) {
        Director director = new Director();
        ServerProduct classicCentOSEnvironment1 = director.createClassicCentOSEnvironment();
        System.out.println("創建第一個環境:" + classicCentOSEnvironment1.getEnvironment());
        director = new Director();
        classicCentOSEnvironment2 = director.createClassicUbuntuEnvironment();
        System.out.println("創建第二個環境:" + classicCentOSEnvironment2.getEnvironment());
        System.out.println("創建第一個環境:" + classicCentOSEnvironment1.getEnvironment());

    }
}

---------------------------------------------------
創建第一個環境:ServerProduct{os='CentOS', language='Java', server='Tomcat', database='Mysql'}
創建第二個環境:ServerProduct{os='Ubuntu', language='Java', server='Tomcat', database='Mysql'}
創建第一個環境:ServerProduct{os='CentOS', language='Java', server='Tomcat', database='Mysql'}

這樣就沒有什麼問題了。每次新建出來的環境都是不同的對象。

總結

優點

建造者模式中,客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。

每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產品對象。由於指揮者類針對抽象建造者編程,增加新的具體建造者無須修改原有類庫的代碼,系統擴展方便,符合“開閉原則”。

可以更加精細地控制產品的創建過程。將複雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰。

缺點

建造者模式所創建的產品具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,不適合使用建造者模式,因此其使用範圍受到一定的限制。

如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大,增加系統的理解難度和運行成本。

Git地址

本篇實例Github地址:https://github.com/stackisok/Design-Pattern/tree/master/src/builder

回到最上方


有什麼不懂或者不對的地方,歡迎留言。
喜歡LZ文章的小夥伴們,可以關注一波,也可以留言,LZ會回你們的。
覺得寫得不錯的小夥伴,歡迎轉載,但請附上原文地址,謝謝^_^!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章