設計模式之建造者模式,demo詳細

序言

在看Retrofit源碼時,可以看到裏面用到了大量的設計模式,如果我們非常瞭解設計模式對理解是很有幫助的,在Rerofit裏有用到建造者模式。

定義

將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以生成不同的表示。建造者模式也是對象創建行模式。

說明: 單看這個定義初學者也是很蒙, 大概意思是不需要關心複雜對象創建過程,只需要知道建造者類型即可,建造者才關心這個複雜對象是如何一步一步創建一個複雜對象的。 根據不同類型的建造者生成不同的複雜的對象。也是有具有良好的擴展性。

建造者模式類圖

建造者模式類圖

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

  • Builder(抽象的建造者) : 它是創建Product對象各個部分的抽象接口。 在該接口一般有兩類接口 ,一種是biuldPartX()方法,用於創建該複雜對象各個部分; 另一種方法是getResult, 它用於返回這個複雜對象。 Build可以是一個接口,也可以是抽象類。
  • ConcreteBuilder(具體的建造者): 它實現了Builder接口,具體實現該複雜對象的各個部分,然後返回具體的複雜對象。
  • Product(產品角色): 它是複雜對象,裏面包含該對象有哪些部分組成。
  • Director(指揮者):它負責對象的建造次序。指揮者和抽象的建造者存在關聯關係,可以在construct中完成複雜對象的創建過程。

上面有提到複雜對象,那什麼是複雜對象呢,簡單來說就是包含多個成員屬性的對象。代碼示例如下:

//產品
class Product{
	private String partA;//定義產品的屬性,屬性可以是其它類型, 值類型和引用類型都行。
	private String partB;
	private String partC;
	//Setter和Getter方法省略就不寫了
}

在抽象建造者定義產品的創建方法和獲取產品對象的方法。代碼示例如下:

//抽象建造者
interface Builder{
	void buildPartA();//創建產品的屬性
	void buildPartB();
	void buildPartC();
	Product getResult(); //返回產品對象

}

抽象建造者中申明瞭一系列的buildPartX()方法,但是具體的實現還是需要具體的建造者。 不同的建造者實現的buildPartX有所區別。代碼示例如下:

//具體的建造者 A
public class AConcreteBuilder implements Builder {
Product productA=new Product();
@Override
public void buildPartA() {
    productA.setPartA("PartA from AConcreteBuilder");
}

@Override
public void buildPartB() {
    productA.setPartA("PartB from AConcreteBuilder");
}

@Override
public void buildPartC() {
    productA.setPartA("PartC from AConcreteBuilder");
}

@Override
public Product getResult() {
    return productA;
}
}

//具體的建造者 B
public class BConcreteBuilder implements Build {
Product productB=new Product();
@Override
public void buildPartA() {
    productB.setPartA("PartA from BConcreteBuilder");
}

@Override
public void buildPartB() {
    productB.setPartA("PartB from BConcreteBuilder");
}

@Override
public void buildPartC() {
    productB.setPartA("PartC from BConcreteBuilder");
}

@Override
public Product getResult() {
    return productB;
}
}

我們可以看到每個建造者實現的東西是不同的。但是返回的產品還是一類的,只是產品的屬性不一樣。

在建造者模式還有個Director角色(導演者或指揮者),該類主要有兩個作用: 其一就是控制產品的創建過程,包括biuldPartX方法是否被調用以及調用的順序; 其二 就是隔離了客戶與創建的過程, Director只需要指揮抽象的建造者(Build),客戶端需要具體的建造者然後調用指揮者的相關方法,返回一個完整的對象(Product)。 代碼示例如下

//指揮者
public class Director {
private Builder mBuilder; //抽象的建造者

public Director(Builder build) {
    this.mBuilder = build;
}
public Product construct(){
    mBuilder.buildPartA();
    mBuilder.buildPartB();
    mBuilder.buildPartC();
    return  mBuilder.getResult();
}
}

//客戶端   代碼片段如下
Builder Abuilder=new AConcreteBuilder();//創建具體的建造者
Director director=new Director(Abuilder);//創建指揮者
Product productA=director.construct();//返回產品A

Builder Bbuilder=new BConcreteBuilder();//創建具體的建造者
Director director=new Director(Bbuilder);//創建指揮者
Product productA=director.construct();//返回產品B

例子

如某個公司要開發個APP(Product),就需要開發者(Builder), 如果有多端的話就需要不同的開發者(ConcreteBuilder),技術經理(Director)就充當指揮者來指示不同的開發者來開發。

APP (Product)

public class APP {
	String code;//代碼
	String note;//註釋及文檔

	public String getCode() {
    	return code;
	}
	public void setCode(String code) {
    	this.code = code;
	}
    public String getNote() {
    	return note;
	}
	public void setNote(String note) {
   	    this.note = note;
	}

	@Override
	public String toString() {
    	return "APP = {" +
            	"code='" + code + '\'' +
            	", note='" + note + '\'' +
            	'}';
	}
}

開發者 (Builder)

public interface Developer {
	void writeCode();//寫代碼

	void writeNote();//寫文檔及註釋

	APP getAPP();//返回APP
}

Andoird開發者(ConcreteBuilder)

public class AndroidDeveloper implements Developer {

	APP app = new APP();

	@Override
	public void writeCode() {
    	app.setCode("Android code");
	}
	@Override
	public void writeNote() {
    	app.setNote("Android note ");
	}
	@Override
	public APP getAPP() {
    	return app;
	}
}

技術經理 (指揮者)

public class TechnicalManager {

	Developer mDeveloper;

	public void setDeveloper(Developer mDeveloper) {
    	this.mDeveloper = mDeveloper;
	}

	public APP getAPP() {
    	mDeveloper.writeCode();
    	mDeveloper.writeNote();
    	return mDeveloper.getAPP();
	}
}

測試:

	public static void main(String[] args) {
    	TechnicalManager manager = new TechnicalManager();//創建技術經理對象(指揮者)
   	 	AndroidDeveloper javaDeveloper = new AndroidDeveloper();//創建Android開發者(具體的建造者)
    	manager.setDeveloper(javaDeveloper);//技術經理指揮Android程序員去幹活
    	APP app = manager.getAPP(); //完成 Android端 APP
    	System.out.println(app);
	}

運行結果:

APP = {code=‘Android code’, note=‘Android note’}

如果公司想在蘋果商店也要上款APP,那就需要ios開發,這樣我們就不用修改源代碼,只需要另創建一個ios的建造者就OK。

ios 開發者(ConcreteBuilder)

public class IosDeveloper implements Developer {
	APP app = new APP();

	@Override
	public void writeCode() {
    app.setCode("ios code");
	}

	@Override
	public void writeNote() {
    	app.setNote("ios note");
 	}

	@Override
	public APP getAPP() {
    	return app;
	}
}

測試:

  public static void main(String[] args) {
    TechnicalManager manager = new TechnicalManager();//創建技術經理對象(指揮者)
    IosDeveloper iosDeveloper = new IosDeveloper();//創建ios開發者(具體的建造者)
    manager.setDeveloper(iosDeveloper);//技術經理指揮ios程序員去幹活
    APP app = manager.getAPP(); //完成 ios端 APP
    System.out.println(app);
}

運行結果:

APP {code=‘ios code’, note=‘ios note’}

如果需要其他端的APP,只需另創建個建造者就可以完成APP。

但是我們看大多數的源碼,裏面的建造者模式是沒有指揮者的(Director),這個又是怎樣實現的呢。 在Android中的彈框(dialog)的實現就用了建造者模式,我們就大致實現下它是怎麼創建的。 源碼中還是很複雜的,這裏只是簡單實現。

在Android中創建一個dialog的代碼

   AlertDialog.Builder builder = new AlertDialog.Builder(this)
    .setTitle("提示")
    .setMessage("消息")
    .setIcon(R.drawable.icon);
    AlertDialog alertDialog=builder.create(); 

這是Android創建dialog最簡單的方式。 現在我們就實現這樣的寫法。

// Product
public class AlertDialog{
	String msg;//消息
	String tilte;//標題
	int icon; //圖標

	@Override
	public String toString() {
    	return "AlertDialog{" +
            	"msg='" + msg + '\'' +
            	", tilte='" + tilte + '\'' +
            	", icon=" + icon +
            	'}';
}
//建造者  (Builder)
	static class Builder{
    	private AlertDialog mDialog=new AlertDialog();

    	public Builder setIcon(int icon){
        	mDialog.icon=icon;
        	return this;
    	}

    	public  Builder setTitle(String title){
        mDialog.tilte=title;
        	return this;
    	}

    	public  Builder setMsg(String msg){
        	mDialog.msg=msg;
        	return this;
    	}

    	public AlertDialog create(){
        	return  mDialog;
    	}
	}
}

測試 :

public static void main(String args[]) {
	//因爲Builder是AlertDialog的成員內部類,所以這樣調用AlertDialog.Builder  
    AlertDialog.Builder builder = new AlertDialog.Builder();
    builder.setIcon(1)
            .setMsg("消息")
            .setTitle("提示");
    AlertDialog dialog = builder.create();
    System.out.println(dialog);
}

運行結果:

AlertDialog{msg=‘消息’, tilte=‘提示’, icon=1}

可以看到我們也按照Android源碼這樣的調用方法創建了自己的dialog。 Android中的dialog實現比我這複雜,dialog屬性更多,邏輯更復雜。

我們可以再看看Retrofit中使用的建造者模式

   Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(API_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .build();

這是創建Retrofit對象。可以看到也是用了建造者模式。 這裏就不說了,下次分析源碼時再說。

總結:建造者模式只要明白四個角色Product、Builder、ConcreteBuilder、Director的作用,就差不多明白建造者模式是怎麼回事了。

優點:

  • 將產品的本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。
  • 每一個具體建造者都是相對獨立的,不依賴其他的具體建造者,可以方便地替換和增加新的具體建造者,用戶使用不同的具體建造者就能得到不同的產品對象。 由於指揮者(Director)是針對抽象的建造者(Builder)編程,增加新的建造者無需修改原來的建造者,符合‘開閉原則’。

缺點:

  • 所創建的產品具有較多的共同點,其組成部分相似。 如果產品之間的差異性很大的話,就不適用建造者模式。
  • 產品的內部變化複雜的話,可能會導致定義很多的具體建造者來應對這樣的變化,這樣會導致系統的複雜性。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章