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等需要做大量自定義設置的。由于通過鏈式調用,使得代碼簡潔易懂,將封裝與擴展很好地結合起來。當然,缺點也很明顯,多了不少類。