建造者模式——五種創建型模式之一

1.前言


單例模式可以創建出一個實例,并且這個實例存在的情況下,不會再創建出同樣的實例。但是,有個明顯的缺點,就是擴展性不高。實際開發中經常會遇到另外一種創建對象的情況,根據用戶需求對實例進行設置。若放在構造函數中,要么加判斷語句,要么重載構造函數,很不靈活;若通過setter注入,會增加許多與功能不相關的方法,而且對象的設置一般放在初始化時,不能讓用戶隨時修改。

2.概念


建造者模式將一個復雜對象的構建與它的表示分離,使得對象專注于功能的展示,隱藏內部的實現。需要注意的是,一旦創建了對象,就不可修改配置了。還有最容易被誤解的第二句,同樣的構建過程可以創建不同的表示,即創建對象的算法應該獨立于它的裝配方式,允許創建結果有不同表示。

3.場景


食品廠準備生產月餅,需要根據市場喜好制作一套模具。然后,通過模具給月餅胚子成形,表面印上花紋。這里需要注意的是,我們可以新建不同的模具,讓食品廠生產不同的月餅。

4.寫法

public final class Mooncakes {
    
    // 1.創建的對象所具有的屬性
    private int mSize;
    private String mName;
    
    private Mooncakes(int size, String name) {
        super();
        mSize = size;
        mName = name;
    }

    // 2.創建的對象所表現的功能
    public void product() {
        System.out.println("開始生產  " + mSize + "號大小  " + " " + mName + "花紋的月餅");
    }
    
    public static class Builder {

        // 3.構造器存儲對象的屬性
        private int mSize = 10;
        private String mName = "";
        
        // 4.向構造器設置對象的屬性
        public Builder setSize(int size) {
            if (size > 0) {
                mSize = size;
            }
            return this;
        }
        
        public Builder setName(String name) {
            if (name != null && !name.equals("")) {
                mName = name;
            }
            return this;
        }
        
        // 5.通過構造器構造對象
        public Mooncakes build() {
            return new Mooncakes(mSize, mName);
        }
        
    }

}
public class Company {

    public static void main(String[] args) {
        // 先制作模具,在生產月餅
        new Mooncakes.Builder().setSize(4).setName("嫦娥").build().product();
        new Mooncakes.Builder().setName("嫦娥").build().product();
        new Mooncakes.Builder().setSize(4).build().product();
    }

}

不知道,大家可有發現一個問題。雖然一個具體的模具與一種月餅綁定,但是模具的制作沒有規范,比較隨意,不符合實際。所以,我們得關注第二點概念。這里有一些誤區,大家可以參考happyhippy的文章,看最后的核心思想就夠了,畢竟我們討論的前提是算法不變。Director 定義了模具的制作規范,具體怎么實施由Builder實現類決定。

// 1.構造復雜對象默認實例
public class Mooncakes {
    
    private int mSize;
    private String mName;
    
    public Mooncakes() {
        super();
        mSize = 10;
        mName = "";
    }
    
    public void setmSize(int mSize) {
        this.mSize = mSize;
    }
    public void setmName(String mName) {
        this.mName = mName;
    }

    @Override
    public String toString() {
        return "Mooncakes [mSize=" + mSize + ", mName=" + mName + "]";
    }

}
// 2.導向器,定義復雜對象的構建算法
public class Director {
    
    private Builder mBuilder;
    
    public Director(Builder builder) {
        super();
        mBuilder = builder;
    }

    // 對于月餅而言,步驟是不會變的,先定型后印花
    public Mooncakes produceMooncakes() {
        return mBuilder.setSize(4).setName("嫦娥").build();
    }

}
// 3.抽象出對象的組裝方式
public abstract class Builder {
    
    protected Mooncakes mCakes = new Mooncakes();
    
    public abstract Builder setSize(int size);
    
    public abstract Builder setName(String name);
    
    public Mooncakes build() {
        return mCakes;
    }

}
// 4.按照正常的方式設置
public class NormalBuilder extends Builder {

    @Override
    public Builder setSize(int size) {
        if (size > 0) {
            mCakes.setmSize(size);
        }
        return this;
    }

    @Override
    public Builder setName(String name) {
        if (name != null && !name.equals("")) {
            mCakes.setmName(name);
        }
        return this;
    }

}
// 5.按照我的方式設置
public class LanceBuilder extends Builder {

    @Override
    public Builder setSize(int size) {
        if (size > 0) {
            mCakes.setmSize(size * 2);
        }
        return this;
    }

    @Override
    public Builder setName(String name) {
        if (name != null && !name.equals("")) {
            mCakes.setmName("歡樂" + name);
        }
        return this;
    }

}
public class Company{

    public static void main(String[] args) {
        // 先制作模具,在生產月餅
        Mooncakes normalCakes = new Director(new NormalBuilder()).produceMooncakes();
        Mooncakes lanceCakes = new Director(new LanceBuilder()).produceMooncakes();
        System.out.println(normalCakes.toString());
        System.out.println(lanceCakes.toString());
    }

}

5.總結


建造者模式在安卓開發中較為常見,主要是調用系統的控件,比如說Dialog、Notification等需要做大量自定義設置的。由于通過鏈式調用,使得代碼簡潔易懂,將封裝與擴展很好地結合起來。當然,缺點也很明顯,多了不少類。

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

推薦閱讀更多精彩內容