Java設計模式之建造者模式(光頭強買電鋸引發的思考)

AWeiLoveAndroid發表於2019-08-22

本文根據光頭強做電鋸的故事,講解一下Java設計模式中的“建造者模式”,故事性更強,配合著程式碼講解,讓大家更輕鬆的掌握“建造者模式”。


一、故事背景

熊出沒 第59集 超級電鋸

Java設計模式之建造者模式(光頭強買電鋸引發的思考)

Java設計模式之建造者模式(光頭強買電鋸引發的思考)

Java設計模式之建造者模式(光頭強買電鋸引發的思考)

(一)什麼是建造者模式?

建造者模式它是一種將複雜物件的構造與其表示分開,以便相同的構造過程可以建立不同的表示的設計模式。

(二)基本組成單元有哪些?

一個完整的建造者模式分為4個部分:

  • 1.建造者(Builder):用於建立Product物件的部分的抽象介面。
  • 2.具體建造者(ConcreteBuilder):通過實現Builder介面構建和組裝產品的一部分。
  • 3.指揮者(Director):它直接Builder介面來構造物件。
  • 4.產品(Product):需要構建的複雜的物件。

(三)使用場景

一般用於複雜的物件內部,比如:一個物件有多個功能,可以在它的內部用多個方法具體描述每個功能,然後呼叫這個類的時候,就可以直自由的構建出這個類物件(比如:new Person().setName("18").setAge(20).build();其實這個Person類就做了具體的物件構建的操作邏輯。),也有網友狹隘的說鏈式呼叫就是建造者模式,其實那是片面的認識,雖然是一種表現形式,但是實際操作中有很多不同的表現形式,不能一概而論。下面就一個例項詳解一下基本使用到複雜多變的使用場景。


二、基本使用場景

(一)各個類的介紹:

光頭強於是去了鎮子上的五金店鋪,,光頭強心理嘀咕著:“不光能砍樹,還能嚇跑熊大熊二,看它還敢來欺負自己。”於是跟那個老闆的說了自己的需求:“我要買一把電手鋸”。老闆說:“不好意思,沒有了,需要預定,預計一個星期之後就到了。”然後光頭強就下單了,老闆就電話通知手電鋸工廠下了訂單,然後工廠開始生產手電鋸。

這回還沒把熊大熊二嚇跑,於是光頭強又跑到鎮子上,找到了五金店的老闆,讓老闆給他一把厲害的鋸子。光頭強這回跟那個老闆的說了自己的需求:“我要一把厲害的電手鋸,上回那個沒有趕走熊大熊二,你這裡有沒有厲害的手電鋸”。老闆逐個都介紹了一遍,光頭強一對比,發現並沒有自己想要的獨一無二的那個。於是跟那個老闆的說了自己的需求:“我需要的是這樣的:調速防誤觸智慧開關、動力強耐高溫散熱好的純銅電機、環保大容量鋰電池、人體工體學包膠防滑防抖手柄、環保防觸電插頭、加厚加固耐磨抗打擊防護罩、高硬度鋸片、然後額外配上LED燈,錢不是問題”。老闆說沒問題,半個月之後過來取吧。光頭強於是交了定金,興奮的回家了。坐等老闆的好訊息了。

車間要準備要投入生產的機器,還有各種原材料和模具:

/**
 * 鏈鋸建築者
 */
public interface ChainsawBuilder {
    // 蓄電池
    void battery();
    // 電動機
    void motor();
    // 減速箱
    void reductionGearbox();
    // 防護罩
    void hood();
    // 手柄
    void handle();
    // 開關
    void switches();
    // 插頭
    void plug();
    // 圓鋸片
    void circularSaw();

    // 獲取鏈鋸(產品)的例項
    Chainsaws getChainsaws();

}
複製程式碼

接下來就是具體的車間按照現有的材料進行生產:

/**
 * 鏈鋸建築者(具體建築者)
 */
public class ChainsawBuilderImpl implements ChainsawBuilder{

    private Chainsaws chainsaws;

    public ChainsawBuilderImpl() {
        chainsaws = new Chainsaws();
    }


    @Override
    public void battery() {
        chainsaws.setBattery("普通鋰電池");
    }

    @Override
    public void motor() {
        chainsaws.setMotor("普通鋁電動機");
    }

    @Override
    public void reductionGearbox() {
        chainsaws.setReductionGearbox("普通減速箱");
    }

    @Override
    public void hood() {
        chainsaws.setHood("普通PVC塑料");
    }

    @Override
    public void handle() {
        chainsaws.setHandle("普通PVC塑料");
    }

    @Override
    public void switches() {
        chainsaws.setSwitches("普通拉線開關");
    }

    @Override
    public void plug() {
        chainsaws.setPlug("普通三口插頭");
    }

    @Override
    public void circularSaw() {
        chainsaws.setCircularSaw("普通鋼鋸片");
    }

    @Override
    public Chainsaws getChainsaws() {
        return chainsaws;
    }
}

複製程式碼

最終產品就具備這些功能:

/**
 * 產品(鏈鋸)
 */
public class Chainsaws {

    // 蓄電池
    private String battery;
    // 電動機
    private String motor;
    // 減速箱
    private String reductionGearbox;
    // 防護罩
    private String hood;
    // 手柄
    private String handle;
    // 開關
    private String switches;
    // 插頭
    private String plug;
    // 圓鋸片
    private String circularSaw;


    public String getBattery() {
        return battery;
    }

    public void setBattery(String battery) {
        this.battery = battery;
    }

    public String getMotor() {
        return motor;
    }

    public void setMotor(String motor) {
        this.motor = motor;
    }

    public String getReductionGearbox() {
        return reductionGearbox;
    }

    public void setReductionGearbox(String reductionGearbox) {
        this.reductionGearbox = reductionGearbox;
    }

    public String getHood() {
        return hood;
    }

    public void setHood(String hood) {
        this.hood = hood;
    }

    public String getHandle() {
        return handle;
    }

    public void setHandle(String handle) {
        this.handle = handle;
    }

    public String getSwitches() {
        return switches;
    }

    public void setSwitches(String switches) {
        this.switches = switches;
    }

    public String getPlug() {
        return plug;
    }


    public void setPlug(String plug) {
        this.plug = plug;
    }

    public String getCircularSaw() {
        return circularSaw;
    }

    public void setCircularSaw(String circularSaw) {
        this.circularSaw = circularSaw;
    }


    @Override
    public String toString() {
        return "Chainsaws{" +
                "\n battery='" + battery + '\'' +
                ", motor='" + motor + '\'' +
                ", reductionGearbox='" + reductionGearbox + '\'' +
                ", hood='" + hood + '\'' +
                ", handle='" + handle + '\'' +
                ", switches='" + switches + '\'' +
                ", plug='" + plug + '\'' +
                ", circularSaw='" + circularSaw + '\'' +
                "鏈鋸已經做好了\n" + '}';
    }


}

複製程式碼

老闆作為一箇中間人的角色,需要跟廠商對接,電話通知建造方,檢視進度如何了:

/**
 * 五金店老闆(驗收方)
 */
public class HardwareStoreBoss {

    // 電話通知建造方,檢視進度如何了
    public Chainsaws notify(ChainsawBuilder builder){

        // 蓄電池
        builder.battery();
        // 電動機
        builder.motor();
        // 減速箱
        builder.reductionGearbox();
        // 防護罩
        builder.hood();
        // 手柄
        builder.handle();
        // 開關
        builder.switches();
        // 插頭
        builder.plug();
        // 圓鋸片
        builder.circularSaw();
        return builder.getChainsaws();
    }
}

複製程式碼

過了幾天,光頭強打電話給五金店老闆。

HardwareStoreBoss hardwareStoreBoss = new HardwareStoreBoss();
複製程式碼

五金店老闆跟光頭強說你等會兒,我先去問問鏈鋸做好了沒,於是:

  Chainsaws chainsaws = hardwareStoreBoss.notify(new ChainsawBuilderImpl());
        System.out.println(chainsaws.toString());
複製程式碼

這時候列印結果是:

Chainsaws{
 battery='普通鋰電池', motor='普通鋁電動機', reductionGearbox='普通減速箱', hood='普通PVC塑料', handle='普通PVC塑料', switches='普通拉線開關', plug='普通三口插頭', circularSaw='普通鋼鋸片'鏈鋸已經做好了
}
複製程式碼

然後五金店老闆去生產那裡取貨,然後再通知光頭強過去取貨。

(二)UML圖解如下:

Java設計模式之建造者模式(光頭強買電鋸引發的思考)


三、新增建造者介面(換一個新鏈鋸)

(一)各個類的介紹:

光頭強拿到貨之後,就興高采烈的去試著砍樹,結果發現砍了幾棵樹,要麼就是沒電了,要麼就是掉鏈子了,這怎麼行?光頭強這回要求老闆退貨,老闆不幹,這樣吧。我給你返回維修。維修費我出。光頭強不幹,堅決要退貨,老闆犟不過,要不這樣,給你換一個效能更高階的鏈鋸,你只要補差價就好了,怎麼樣,工廠那邊正好有批次在做的,給你預定一個,一週內可以就拿到貨了。光頭強爽快的答應了。

於是工廠這邊也利用原有的功能(介面ChainsawBuilder),加入新的一些功能(新建一個類ChainsawBuilderImpl2),就開始製造了。基本功能都差不多的,只是換一些零部件,如下所示:

/**
 * 鏈鋸建築者(具體建築者)
 */
public class ChainsawBuilderImpl2 implements ChainsawBuilder{

    private Chainsaws chainsaws;

    public ChainsawBuilderImpl2() {
        chainsaws = new Chainsaws();
    }


    @Override
    public void battery() {
        chainsaws.setBattery("環保大容量鋰電池");
    }

    @Override
    public void motor() {
        chainsaws.setMotor("動力強耐高溫散熱好的純銅電機");
    }

    @Override
    public void reductionGearbox() {
        chainsaws.setReductionGearbox("減震變頻高功率變速箱");
    }

    @Override
    public void hood() {
        chainsaws.setHood("加厚加固耐磨抗打擊防護罩");
    }

    @Override
    public void handle() {
        chainsaws.setHandle("人體工體學包膠手柄");
    }

    @Override
    public void switches() {
        chainsaws.setSwitches("調速防誤觸智慧開關");
    }

    @Override
    public void plug() {
        chainsaws.setPlug("環保防觸電插頭");
    }

    @Override
    public void circularSaw() {
        chainsaws.setCircularSaw("高硬度鋸片");
    }

    @Override
    public Chainsaws getChainsaws() {
        return chainsaws;
    }
}

複製程式碼

同樣的過了幾天,光頭強打電話給五金店老闆。

HardwareStoreBoss hardwareStoreBoss = new HardwareStoreBoss();
複製程式碼

五金店老闆跟光頭強說你等會兒,我先去問問鏈鋸(這時候是:新鏈鋸)做好了沒,於是:

  Chainsaws chainsaws = hardwareStoreBoss.notify(new ChainsawBuilderImpl2());
        System.out.println(chainsaws.toString());
複製程式碼

這時候列印結果是:

Chainsaws{
 battery='環保大容量鋰電池', motor='動力強耐高溫散熱好的純銅電機', reductionGearbox='減震變頻高功率變速箱', hood='加厚加固耐磨抗打擊防護罩', handle='人體工體學包膠手柄', switches='調速防誤觸智慧開關', plug='環保防觸電插頭', circularSaw='高硬度鋸片'鏈鋸已經做好了
}
複製程式碼

於是光頭強就去拿到新鏈鋸愉快的砍樹去了。

(二)UML圖解如下:


四、減少指揮者角色(光頭強聯絡廠家定製)

(一)各個類的介紹:

光頭強發現一個鏈鋸不夠用了,還想再買一個,但是每次通過五金店老闆去詢問太麻煩了,於是通過網上官網查詢,找到了生產廠家的售後電話,直接聯絡他們,又重新定製了一個鏈鋸。

廠家看光頭強已經是第三次購買,算是VIP使用者了,特意為他開了一個後門,車間有同意協調(鏈鋸建造者類)專門管理。

/**
 * 鏈鋸建築者
 */
public interface ChainsawBuilder {

    // 蓄電池
    ChainsawBuilder battery(String name);
    // 電動機
    ChainsawBuilder motor(String name);
    // 減速箱
    ChainsawBuilder reductionGearbox(String name);
    // 防護罩
    ChainsawBuilder hood(String name);
    // 手柄
    ChainsawBuilder handle(String name);
    // 開關
    ChainsawBuilder switches(String name);
    // 插頭
    ChainsawBuilder plug(String name);
    // 圓鋸片
    ChainsawBuilder circularSaw(String name);

    // 獲取鏈鋸(產品)的例項
    Chainsaws getChainsaws();

}
複製程式碼

這樣一來,可以快速由專人負責找到對應的零件。

具體的生產建築者這邊也沒閒著,也跟著做了改變,之前是規矩寫死的,我這裡有什麼,客戶才能定製什麼(方法傳入的String型別的引數),現在是可互需要的是什麼,我這邊就負責生產什麼樣的。具體如下:

/**
 * 鏈鋸建築者(具體建築者)
 */
public class ChainsawBuilderImpl2 implements ChainsawBuilder {

    private Chainsaws chainsaws;

    public ChainsawBuilderImpl2() {
        chainsaws = new Chainsaws();
    }

    @Override
    public ChainsawBuilder battery(String name) {
        chainsaws.setBattery(name);
        return this;
    }

    @Override
    public ChainsawBuilder motor(String name) {
        chainsaws.setMotor(name);
        return this;
    }

    @Override
    public ChainsawBuilder reductionGearbox(String name) {
        chainsaws.setReductionGearbox(name);
        return this;
    }

    @Override
    public ChainsawBuilder hood(String name) {
        chainsaws.setHood(name);
        return this;
    }

    @Override
    public ChainsawBuilder handle(String name) {
        chainsaws.setHandle(name);
        return this;
    }

    @Override
    public ChainsawBuilder switches(String name) {
        chainsaws.setSwitches(name);
        return this;
    }

    @Override
    public ChainsawBuilder plug(String name) {
        chainsaws.setPlug(name);
        return this;
    }

    @Override
    public ChainsawBuilder circularSaw(String name) {
        chainsaws.setCircularSaw(name);
        return this;
    }

    @Override
    public Chainsaws getChainsaws() {
        return chainsaws;
    }
}

複製程式碼

光頭強這時候想問廠家做好了沒,告訴廠家自己要做的零部件的型別,廠家就一次性安排生產了:

 ChainsawBuilderImpl2 chainsawBuilderImpl2 = new ChainsawBuilderImpl2();
Chainsaws chainsaws = chainsawBuilderImpl2.battery("環保大容量鋰電池")
                .motor("動力強耐高溫散熱好的純銅電機")
                .reductionGearbox("減震變頻高功率變速箱")
                .hood("加厚加固耐磨抗打擊防護罩")
                .handle("人體工體學包膠手柄")
                .switches("調速防誤觸智慧開關")
                .plug("環保防觸電插頭")
                .circularSaw("高硬度鋸片")
                .getChainsaws();
複製程式碼

這時候列印結果還是一樣的:

Chainsaws{
 battery='環保大容量鋰電池', motor='動力強耐高溫散熱好的純銅電機', reductionGearbox='減震變頻高功率變速箱', hood='加厚加固耐磨抗打擊防護罩', handle='人體工體學包膠手柄', switches='調速防誤觸智慧開關', plug='環保防觸電插頭', circularSaw='高硬度鋸片'鏈鋸已經做好了
}
複製程式碼

(二)UML圖解如下:


Java設計模式之建造者模式(光頭強買電鋸引發的思考)

相關文章