1. 程式人生 > >Android中的設計模式之構建者模式

Android中的設計模式之構建者模式

參考

  • 《設計模式:可複用面向物件軟體的基礎 》3.2 Builder 生成器–物件建立型模式
  • 《Android原始碼設計模式解析與實戰》第3章 Builder模式

意圖

將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。

適用性

  • 相同的方法,不同的執行順序,產生不同的事件結果時。
  • 多個部件或零件,都可以裝配到一個物件中,但是產生的執行結果又不相同時。
  • 產品類非常複雜,或者產品類中的呼叫順序不同產生了不同的作用,這個時候使用建造者模式非常合適。
  • 當初始化一個物件特別複雜,如引數多,且很多引數都具有預設值時。

結構

Builder模式

  • Product
    • 表示被構造的複雜物件
    • 包含定義組成部件的類,包括將這些部件裝配成最終產品的介面
  • Builder 抽象Builder類,為建立一個Product物件的各個部件指定抽象介面,規範產品的組建,一般是由子類實現具體的組建過程。
  • ConcreteBuilder 具體的Builder實現類
  • Director 使用Builder介面進行構造

協作

  • 客戶建立Director物件,並用它所想要的Builder物件進行配置。
  • 一旦產品部件被生成,Builder就會通知生成器
  • 生成器處理Builder的請求,並將部件新增到該產品中。
  • 客戶從生成器中檢索產品

協作序列圖

例子1:RTF閱讀器

一個RTF(Rich Text Format)閱讀器應能將RTF轉換為多種正文格式。該閱讀器可以將RTF文件轉換為普通ASCII文字或者一個能以互動方式編輯的正文視窗元件。但問題是在於可能轉換的數目是無限的。因此要能夠很容易地實現新的轉換的增加,同時卻不改變RTF閱讀器。

一種解決辦法就是運用Builder模式,用一個可以將RTF轉換成另一種正文表示的TextConverter物件配置這個RTFReader類。當RTFReader對RTF文件進行語法分析時,它使用TextConverter去做轉換。

RTFReader類設計

每種轉換器類將建立和裝配一個複雜物件的機制隱含在抽象介面的後面。轉換器獨立於閱讀器,閱讀器負責對一個RTF文件進行語法分析。

每一個轉換器類可以作為生成器builder,而閱讀器作為director。Builder模式將分析文字格式的演算法與描述怎樣建立和表示一個轉換後格式的演算法分離開來。這使得我們可以重用RTFReader的語法分析演算法,分局RTF文件建立不同的正文表示–僅需使用不同的TextConverter的子類配置該RTFReader即可。

例子2:組裝電腦

我想隨意組裝一臺電腦,比如一臺Inter主機板,Retina顯示屏,MacOs的電腦

計算機的組裝過程較為負複雜,並且組裝順序是不固定的,所以我們可以用Buider模式。

組裝電腦

示例程式碼:

// 電腦基礎抽象類
public abstract class Computer {
    protected String mBoard;
    protected String mDisplay;
    protected String mOS;
    protected Computer(){}
//設定主機板
public void setBoard(String board){
    this.mBoard=board;
}
//設定顯示器
public void setDisplay(String display) {
    mDisplay=display;
}
//設定作業系統
public abstract void  setOS();

@Override
    public String toString() {
    StringBuilder stringBuilder=new StringBuilder();
    if (mBoard!=null) {
        stringBuilder.append("myBoard is:"+mBoard);
    }
    if (mDisplay!=null) {
        stringBuilder.append("\nmDisplay is:"+mDisplay);
    }
    if (mOS!=null) {
        stringBuilder.append("\nmyOS is:"+mOS);
    }
    return stringBuilder.toString();
    }
}

//Macbook電腦,實現了setOs
public class MacBook  extends Computer{

    @Override
    public void setOS() {
        mOS="Mac _S X 10.10";
    }

}

// 抽象Builder
public abstract class Builder{
  abstract  Buider buildBoard(String board);
  abstract  Buider buildDisplay(String display);
  abstract  Buider buildOS();
  abstract Computer create();
}

//具體的一個Builder類
public class MacBookBuilder extends Buider {
    private Computer mComputer=new MacBook();

    @Override
    public Buider buildBoard(String board) {
        mComputer.setBoard(board);
        return this;
    }

    @Override
    public Buider buildDisplay(String display) {
        mComputer.setDisplay(display);
        return this;
    }

    @Override
    public Buider buildOS() {
        mComputer.setOS();
        return this;
    }

    @Override
    public Computer create() {
        return mComputer;
    }
}
// Director類,負責構造Computer
public class Director{
    Builder mBuilder = null;
    public Director(Builder builder){
        mBuilder = builder;
    }
    public void construct(String board,String display){
        mBuilder.buildBoard(board);
        mBuilder.buildDisplay(display);
        mBuilder.buildOs();
    }
}

//使用
public static void main(String[] args) {
        Builder macBookBuilder=new MacBookBuilder();
        Director director = new Director(macBookBuilder);
        // 使用Director構造
        director.construct(英特爾主機板,retina);
        System.out.println(macBookBuilder.create().toString())
        // 通常我們都會通過Builder的鏈式呼叫省略Director類,比如如下所示
        System.out.println(macBookBuilder.buildBoard("英特爾主機板")
        .buildDisplay("retina")
        .buildOS()
        .create().toString());
    }

結果:
myBoard is:英特爾主機板
mDisplay is:retina
myOS is:Mac _S X 10.10

效果

  • 它使你可以改變一個產品的內部表示
  • 它將構造程式碼和表示程式碼分開
  • 它使你可對構造過程進行更精細的控制
  • 《Effective java》書中建議如果構造一個物件複雜,需要傳入很多引數,不妨採用Builder模式,有效減少了傳參失誤。
  • 當然缺點是增加了程式碼量。

例子3 Android中的AlertDialog.Builder

// todo 後更