建造者模式

1.建造者模式前言

建造者模式是較爲複雜的創建型模式,它將客戶端與包含多個組成部分(或部件)的複雜對象的創建過程分離,客戶端無須知道複雜對象的內部組成部分與裝配方式,只需要知道所需建造者的類型即可。它關注如何一步一步創建一個複雜對象,不同的具體建造者定義了不同的創建過程,且具體建造者相互獨立,增加新的建造者非常方便,無須修改已有代碼,系統具有較好的擴展性。

2.建造者模式定義

建造者模式(Builder Pattern):將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。建造者模式是一種對象創建型模式。

3.建造者模式結構圖

在建造者模式結構圖中包含如下幾個角色:

抽象建造者(Builder):它爲創建一個產品Product對象的各個部件指定抽象接口,在該接口中一般聲明兩類方法,一類方法是buildPartX(),它們用於創建複雜對象的各個部件;另一類方法是getResult(),它們用於返回複雜對象。Builder既可以是抽象類,也可以是接口。

具體建造者(ConcreteBuilder):它實現了Builder接口,實現各個部件的具體構造和裝配方法,定義並明確它所創建的複雜對象,也可以提供一個方法返回創建好的複雜產品對象。

產品角色(Product):它是被構建的負責對象,包含多個組成部件,具體建造者創建該產品的內部表示並定義它的裝配過程。

指揮者(Director):指揮者又稱導演類,它負責安排複雜對象的建造次序,指揮者與抽象建造者之間存在關聯關係,可以在其construct()建造方法中調用建造者對象的部件構造與裝配方法,完成複雜對象的建造。客戶端一般只需要與指揮者進行交互,在客戶端確定具體建造者的類型,並實例化具體建造者對象,然後通過指揮者類的構造函數或者Setter方法將該對象傳入指揮者類中。

在建造者模式的定義中提到了複雜對象,那麼什麼是複雜對象?簡單來說,複雜對象是指那些包含多個成員屬性的對象,這些成員屬性也稱爲部件或零件,如汽車包括方向盤、發動機、輪胎等部件,電子郵件包括發件人、收件人、主題、內容、附件等部件,一個典型的複雜對象代碼示例如下:

複雜對象

public class Product {

    private String partA;
    private String partB;
    private String partC;

    public String getPartA() {
        return partA;
    }

    public void setPartA(String partA) {
        this.partA = partA;
    }

    public String getPartB() {
        return partB;
    }

    public void setPartB(String partB) {
        this.partB = partB;
    }

    public String getPartC() {
        return partC;
    }

    public void setPartC(String partC) {
        this.partC = partC;
    }

}

抽象建造者類

public abstract class Builder {

    protected Product product = new Product();

    public abstract void buildPartA();
    public abstract void buildPartB();
    public abstract void buildPartC();

    public Product getResult() {
        return product;
    }

}

ConcreteBuilder中實現了buildPartX()方法,通過調用Product的setPartX()方法可以給產品對象的成員屬性賦值。不同的具體建造者在實現buildPartX()方法時將有所區別,如setPartX()方法的參數可能不一樣,在有些具體建造者類中某些setPartX()方法無須實現。而這些對於客戶端來說都無須關心,客戶端只需知道具體建造者類型即可。

指揮者類

public class Director {

    private Builder builder;

    public Director(Builder builder) {
        super();
        this.builder = builder;
    }

    public void setBuilder(Builder builder) {
        this.builder = builder;
    }

    public Product construct() {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
        return builder.getResult();
    }

}

客戶端代碼

...
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();
...

建造者模式與抽象工廠模式有點相似,但是建造者模式返回一個完整的複雜產品,而抽象工廠模式返回一系列相關的產品;在抽象工廠模式中,客戶端通過選擇具體工廠來生成所需對象,而在建造者模式中,客戶端通過指定具體建造者類型並指導Director類如何去生成對象,側重於一步步構造一個複雜對象,然後將結果返回。如果將抽象工廠模式看成一個汽車配件生產廠,生成不同類型的汽車配件,那麼建造者模式就是一個汽車組裝廠,通過對配件進行組裝返回一輛完整的汽車。

4.建造者模式實例

Sunny公司開發人員決定使用建造者模式來實現遊戲角色的創建,其基本結構如下圖所示:

上圖中,ActorController充當指揮者,ActorBuilder充當抽象建造者,HeroBuilder、AngelBuilder和DevilBuilder充當具體建造者,Actor充當複雜產品。

具體代碼如下

工程目錄結構

角色類:複雜產品

package cn.red.builder.impl;

public class Actor {

    private String type;
    private String sex;
    private String face;
    private String costume;
    private String hairstyle;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getFace() {
        return face;
    }

    public void setFace(String face) {
        this.face = face;
    }

    public String getCostume() {
        return costume;
    }

    public void setCostume(String costume) {
        this.costume = costume;
    }

    public String getHairstyle() {
        return hairstyle;
    }

    public void setHairstyle(String hairstyle) {
        this.hairstyle = hairstyle;
    }

}

角色建造器:抽象建造者

package cn.red.builder.impl;

public abstract class ActorBuilder {

    protected Actor actor = new Actor();

    public abstract void buildType();
    public abstract void buildSex();
    public abstract void buildFace();
    public abstract void buildCostume();
    public abstract void buildHairstyle();

    //工廠方法,返回一個完整的遊戲角色對象
    public Actor createActor(){
        return actor;
    }
}

英雄角色建造器:具體建造者

package cn.red.builder.impl;

public class HeroBuilder extends ActorBuilder {

    @Override
    public void buildType() {
        actor.setType("英雄");
    }

    @Override
    public void buildSex() {
        actor.setSex("男");
    }

    @Override
    public void buildFace() {
        actor.setFace("英俊");
    }

    @Override
    public void buildCostume() {
        actor.setCostume("盔甲");
    }

    @Override
    public void buildHairstyle() {
        actor.setHairstyle("飄逸");
    }

}

天使建造器:具體建造者

package cn.red.builder.impl;

public class AngelBuilder extends ActorBuilder {

    @Override
    public void buildType() {
        actor.setType("天使");
    }

    @Override
    public void buildSex() {
        actor.setSex("女");
    }

    @Override
    public void buildFace() {
        actor.setFace("漂亮");
    }

    @Override
    public void buildCostume() {
        actor.setCostume("白色長裙");
    }

    @Override
    public void buildHairstyle() {
        actor.setHairstyle("披肩長髮");
    }

}

惡魔建造器:具體建造者

package cn.red.builder.impl;

public class DevilBuilder extends ActorBuilder {

    @Override
    public void buildType() {
        actor.setType("惡魔");
    }

    @Override
    public void buildSex() {
        actor.setSex("妖");
    }

    @Override
    public void buildFace() {
        actor.setFace("醜陋");
    }

    @Override
    public void buildCostume() {
        actor.setCostume("黑衣");
    }

    @Override
    public void buildHairstyle() {
        actor.setHairstyle("光頭");
    }

}

角色創建控制器:指揮者

package cn.red.builder.impl;

public class ActorController {

    //逐步構建複雜產品對象
    public Actor construct(ActorBuilder ab){
        Actor actor;
        ab.buildType();
        ab.buildSex();
        ab.buildFace();
        ab.buildCostume();
        ab.buildHairstyle();
        actor = ab.createActor();
        return actor;
    }

}

客戶端測試代碼:

package cn.red.builder.impl;

public class Client {

    public static void main(String[] args) {
        //針對抽象建造者編程
        ActorBuilder ab = new AngelBuilder();
        ActorController ac = new ActorController();
        //通過指揮者創建完整的產品對象
        Actor actor = ac.construct(ab);

        System.out.println("外觀:" + actor.getType());
        System.out.println("性別:" + actor.getSex());
        System.out.println("面容:" + actor.getFace());
        System.out.println("服裝:" + actor.getCostume());
        System.out.println("髮型:" + actor.getHairstyle());
    }

}

輸出結果:

外觀:天使
性別:女
面容:漂亮
服裝:白色長裙
髮型:披肩長髮

在建造模式中,客戶端只需實例化智慧者類,指揮者類針對抽象建造者編程,客戶根據需要傳入具體的建造者類型,指揮者將指導具體建造者一步一步構造一個完整的產品(逐步調用具體建造者的buildX()方法),相同的構造過程可以創建完全不同的產品。在遊戲角色實例中,如果需要更換角色,只需要更換具體角色建造者類即可;如果需要增加新角色,可以增加一個新的具體角色建造者類作爲抽象建造者類的子類,原有代碼無須修改,完全符合“開閉原則”。

5.建造者模式總結

建造者模式的核心在於如何一步步構建一個包含多個組成部件的完整對象,使用相同的構建過程構建不同的產品,在軟件開發中,如果我們需要創建複雜對象並希望系統具備很好的靈活性和可擴展性可以考慮使用建造者模式。

1.主要優點

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

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

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

2.主要缺點

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

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

6.適用場景

(1)需要生產的產品對象由複雜的內部結構,這些產品對象通常包含多個成員屬性。

(2)需要生產的產品對象的屬性相互依賴,需要指定其生成順序。

(3)對象的創建過程獨立於創建該對象的類。在建造者模式中通過引入了智慧者類,將創建過程封裝在指揮者類中,而不在建造者類和客戶類中。

(4)隔離複雜對象的創建和使用,並使得相同的創建過程可以創建不同的產品。

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