天天看點

設計模式(建立型)之建造者模式(Builder Pattern)

PS一句:最終還是選擇CSDN來整理發表這幾年的知識點,該文章平行遷移到CSDN。因為CSDN也支援MarkDown文法了,牛逼啊!

【工匠若水 http://blog.csdn.net/yanbober】 閱讀前一篇《設計模式(建立型)之單例模式(Singleton Pattern)》 http://blog.csdn.net/yanbober/article/details/45312675

概述

建造者模式将用戶端與包含多個組成部分的複雜對象的建立過程分離,用戶端壓根不用知道複雜對象的内部組成部分與裝配方式,隻需要知道所需建造者的類型即可。它關注如何一步一步建立一個的複雜對象,不同的具體建造者定義了不同的建立過程,且具體建造者互相獨立,增加新的建造者非常友善,無須修改已有代碼,系統具有較好的擴充性。

問題來了。。。

你可能會有疑惑,建造者模式和抽象工廠模式有啥差別呢?

其實,在建造者模式裡有個指導者,由指導者來管理建造者,使用者是與指導者聯系的,指導者聯系建造者最後得到産品。即建造模式可以強制實行一種分步驟進行的建造過程。而抽象工廠模式不具備最終的這個直接建立功能。建造者模式與工廠模式是極為相似的,總體上,建造者模式僅僅隻比工廠模式多了一個“導演類”的角色。假如把這個導演類看做是最終調用的用戶端,那麼剩餘的部分就可以看作是一個簡單的工廠模式了。

與工廠模式相比,建造者模式一般用來建立更為複雜的對象,因為對象的建立過程更為複雜,是以将對象的建立過程獨立出來組成一個新的導演類。

也就是說,工廠模式是将對象的全部建立過程封裝在工廠類中,由工廠類向用戶端提供最終的産品;而建造者模式中,建造者類一般隻提供産品類中各個元件的建造,而将具體建造過程傳遞給導演類。由導演類負責将各個元件按照特定的規則組建為産品,然後将組建好的産品傳遞給用戶端。

設計模式(建立型)之建造者模式(Builder Pattern)

核心

概念: 将一個複雜對象的建構與它的表示分離,使得同樣的建構過程可以建立不同的表示。建造者模式是一種對象建立型模式。

重點: 建造者模式結構重要核心子產品:

Builder(抽象建造者)

它為建立一個産品對象的各個部件指定抽象接口,在該接口中一般聲明兩類方法,一類方法是buildXXX(),它們用于建立複雜對象的各個部件;另一類方法是getXXX(),它們用于傳回複雜對象。Builder既可以是抽象類,也可以是接口。

ConcreteBuilder(具體建造者)

它實作了Builder接口,實作各個部件的具體構造和裝配方法,定義并明确它所建立的複雜對象,也可以提供一個方法傳回建立好的複雜産品對象。

Product(産品角色)

它是被建構的複雜對象,包含多個組成部件,具體建造者ConcreteBuilder建立該産品的内部表示并定義它的裝配過程。

Director(指揮者)

指揮者又稱為導演類,它負責安排複雜對象的建造次序,指揮者與抽象建造者之間存在關聯關系,可以在其construct()建造方法中調用建造者對象的部件構造與裝配方法,完成複雜對象的建造。用戶端一般隻需要與指揮者進行互動,在用戶端确定具體建造者的類型,并執行個體化具體建造者對象,然後通過指揮者類的構造函數或者Setter方法将該對象傳入指揮者類中。

什麼是複雜對象:是指那些包含多個成員屬性的對象,這些成員屬性也稱為部件或零件,如程式猿要會識字、會數學、會程式設計語言,會設計模式等等。

使用場景

需要生成的産品對象有複雜的内部結構,每一個内部成分本身可以是對象,也可以僅僅是一個對象的一個組成部分。

需要生成的産品對象的屬性互相依賴。建造模式可以強制實行一種分步驟進行的建造過程,是以,如果産品對象的一個屬性必須在另一個屬性被指派之後才可以被指派,使用建造模式是一個很好的設計思想。

在對象建立過程中會使用到系統中的其他一些對象,這些對象在産品對象的建立過程中不易得到。

程式猿執行個體

如下執行個體就是一個建造者模式的簡單實作,具體ProgramMonkey就是産品角色,Builder就是抽象建造者,ConcreteProgramMonkey就是具體建造者,Director就是導演指揮者,負責創造兩個程式猿(我們要造人了),一個Low逼,一個大牛High。

package yanbober.github.io;
//Product(産品角色)
class ProgramMonkey {
    private boolean mIsLiterated;
    private boolean mKnowMath;
    private String mLanguage;
    private boolean mKnowDesign;

    public boolean ismIsLiterated() {
        return mIsLiterated;
    }

    public void setmIsLiterated(boolean mIsLiterated) {
        this.mIsLiterated = mIsLiterated;
    }

    public boolean ismKnowMath() {
        return mKnowMath;
    }

    public void setmKnowMath(boolean mKnowMath) {
        this.mKnowMath = mKnowMath;
    }

    public String getmLanguage() {
        return mLanguage;
    }

    public void setmLanguage(String mLanguage) {
        this.mLanguage = mLanguage;
    }

    public boolean ismKnowDesign() {
        return mKnowDesign;
    }

    public void setmKnowDesign(boolean mKnowDesign) {
        this.mKnowDesign = mKnowDesign;
    }

    public void show() {
        System.out.println("\rIsLiterated="+mIsLiterated+"\n"
                            +"KnowMath="+mKnowMath+"\n"
                            +"Language="+mLanguage+"\n"
                            +"KnowDesign="+mKnowDesign+"\n");
    }
}
//Builder(抽象建造者)
abstract class Builder {
    public abstract void buildIsLiterated(boolean arg);
    public abstract void buildKnowMath(boolean arg);
    public abstract void buildLanguage(String arg);
    public abstract void buildKnowDesign(boolean arg);

    public abstract ProgramMonkey getMonkey();
}
//ConcreteBuilder(具體建造者)
class ConcreteProgramMonkey extends Builder {
    private  ProgramMonkey mMonkey = new ProgramMonkey();

    @Override
    public void buildIsLiterated(boolean arg) {
        mMonkey.setmIsLiterated(arg);
    }

    @Override
    public void buildKnowMath(boolean arg) {
        mMonkey.setmKnowMath(arg);
    }

    @Override
    public void buildLanguage(String arg) {
        mMonkey.setmLanguage(arg);
    }

    @Override
    public void buildKnowDesign(boolean arg) {
        mMonkey.setmKnowDesign(arg);
    }

    @Override
    public ProgramMonkey getMonkey() {
        return mMonkey;
    }
}
//Director(指揮者)
class Director {
    private Builder builder = new ConcreteProgramMonkey();

    public ProgramMonkey getMonkeyLow() {
        builder.buildIsLiterated(true);
        builder.buildKnowMath(true);
        builder.buildLanguage("Android");
        builder.buildKnowDesign(false);

        return builder.getMonkey();
    }

    public ProgramMonkey getMonkeyHigh() {
        builder.buildIsLiterated(true);
        builder.buildKnowMath(true);
        builder.buildLanguage("Android/Java/Designer");
        builder.buildKnowDesign(true);

        return builder.getMonkey();
    }
}

public class Main {
    public static void main(String[] args) {
        Director director = new Director();
        ProgramMonkey monkey = director.getMonkeyLow();
        monkey.show();
        monkey = director.getMonkeyHigh();
        monkey.show();
    }
}
           

技巧Tips:依舊可以使用配置與反射實作自動适應。

總結一把

建造者模式優點:

  • 建造者模式中,用戶端不必知道産品内部組成的細節,将産品本身與産品的建立過程解耦,使得相同的建立過程可以建立不同的産品對象。
  • 每一個具體建造者都相對獨立,而與其他的具體建造者無關,是以可以很友善地替換具體建造者或增加新的具體建造者,使用者使用不同的具體建造者即可得到不同的産品對象。由于指揮者類針對抽象建造者程式設計,增加新的具體建造者無須修改原有類庫的代碼,系統擴充友善,符合“開閉原則”。
  • 可以更加精細地控制産品的建立過程。将複雜産品的建立步驟分解在不同的方法中,使得建立過程更加清晰。

建造者模式缺點:

  • 建造者模式所建立的産品具有較多的共同點,其組成部分相似,如果産品之間的差異性很大,不适合使用建造者模式,是以其使用範圍受到一定的限制。
  • 如果産品的内部變化複雜,可能會導緻需要定義很多具體建造者類來實作這種變化,導緻系統變得很龐大,增加系統的了解難度和運作成本。

【工匠若水 http://blog.csdn.net/yanbober】 繼續閱讀《設計模式(建立型)之原型模式(Prototype Pattern)》 http://blog.csdn.net/yanbober/article/details/45363525