Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android : Builder模式 詳解及學習使用

Android : Builder模式 詳解及學習使用

編輯:關於Android編程

Builder模式是一種設計模式,最初被介紹於《設計模式:可復用面向對象軟件的基礎》,目前在Java及Android中用處更是十分廣泛,因此基本的了解與學習應當掌握。

一. Builder模式介紹

首先從它的定義開始介紹:

Builder模式:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。

一般而言,Builder模式主要由四個部分組成:

Product :被構造的復雜對象,ConcreteBuilder 用來創建該對象的內部表示,並定義它的裝配過程。 Builder :抽象接口,用來定義創建 Product 對象的各個組成部分的組件。 ConcreteBuilder : Builder接口的具體實現,可以定義多個,是實際構建Product 對象的地方,同時會提供一個返回 Product 的接口。 Director : Builder接口的構造者和使用者。

以代碼的形式來進行說明,首先創建Product 類:

public class Product {
    private String partOne;
    private String partTwo;

    public String getPartOne() {
        return partOne;
    }

    public void setPartOne(String partOne) {
        this.partOne = partOne;
    }

    public String getPartTwo() {
        return partTwo;
    }

    public void setPartTwo(String partTwo) {
        this.partTwo = partTwo;
    }
}

創建Builder接口:

public interface Builder {
    public void buildPartOne();
    public void buildPartTwo();
    public void getProduct();
}

創建兩個ConcreteBuilder 類,即實現Builder接口:

public class ConcreteBuilderA implements Builder {

    private Product product;

    @Override
    public void buildPartOne() {   
    }

    @Override
    public void buildPartTwo() {
    }

    @Override
    public Product getProduct() {
        return product;
    }
}
public class ConcreteBuilderB implements Builder {

    private Product product;

    @Override
    public void buildPartOne() {   
    }

    @Override
    public void buildPartTwo() {
    }

    @Override
    public Product getProduct() {
        return product;
    }
}

最後創建Director

public class Director {
    private Builder builder;

    public Director(Builder builder){
        this.builder = builder;
    }

    public  void buildProduct(){
        this.builder.buildPartOne();
        this.builder.buildPartTwo();
    }

    public Product getProduct(){
        return this.builder.getProduct();
    }
}





二. Builder模式進化

以上代碼只是最基本的展示了Builder模式,基於定義的介紹。這種基本模式重點在於:抽象出對象創建的步驟,並通過調用不同的具體實現從而得到不同的結果。 但是在實際運用中並非是以上形式,而是進化成另一種體現形式,目的在於 減少對象創建過程中引入的多個重載構造函數、可選參數以及setter過度使用導致不必要的復雜性。



下面還是以代碼的形式來進行講解,只是這次更加具體到一個熟悉的對象User,假以它有以下屬性,且都是不可變(final)的。【應盡量將屬性值定義為不可變】

public class User {
    private final String mName;     //必選
    private final String mGender;   //可選
    private final int mAge;         //可選
    private final String mPhone;    //可選
}

這個 User類中 mName屬性是必選的,其余的可選,接下來該如何構造這個實例呢?在此有兩個前提:

所有屬性值以聲明為 final,因此必須在構造函數中對這些屬性初始化,否則編譯不通過。 可是以上屬性值分為必選可選,所以構造函數需要提供不同的參數組合的方法。(即可選參數可以忽略)

方案一:

因此,綜上兩個前提,最直接的一個方案是定義多個重載的構造函數,其中一個構造函數只接收必選參數,其余的構造函數不僅要接收必選參數,還要接收不同可選參數的組合,代碼如下:

public class User {
    private final String mName;     //必選
    private final String mGender;   //可選
    private final int mAge;         //可選
    private final String mPhone;    //可選

    public User(String mName) {
        this(mName, "");
    }

    public User(String mName,String mGender) {
        this(mName, mGender, 0);
    }

    public User(String mName, String mGender, int mAge) {
        this(mName, mGender, mAge, "");
    }

    public User(String mName, String mGender, int mAge, String mPhone) {
        this.mName = mName;
        this.mGender = mGender;
        this.mAge = mAge;
        this.mPhone = mPhone;
    }
}

這種構造函數的方式雖然簡單,但是 只適用於少量屬性的情況,一旦屬性增多,構造函數的數量也會隨著線性增長,因此並不好閱讀及維護。



方案二:

第二種方案是遵循 JavaBeans 規范,定義一個默認的無參數構造函數,並為類的每個屬性都提供getters 和 setters函數,代碼如下:

public class User {
    private String mName;     //必選
    private String mGender;   //可選
    private int mAge;         //可選
    private String mPhone;    //可選

    public String getName() {
        return mName;
    }

    public void setName(String mName) {
        this.mName = mName;
    }

    public String getGender() {
        return mGender;
    }

    public void setGender(String mGender) {
        this.mGender = mGender;
    }

    public int getAge() {
        return mAge;
    }

    public void setAge(int mAge) {
        this.mAge = mAge;
    }

    public String getPhone() {
        return mPhone;
    }

    public void setPhone(String mPhone) {
        this.mPhone = mPhone;
    }
}

這種方案相較於第一種方案的好處是易於閱讀和維護,使用者可以創建一個空實例User,並只設置需要的屬性值,可是此方案有兩個缺點:

User類是可變的,禁锢了對象的可變性。 User類的實例狀態不連續。如果想要創建一個同時具有所有屬性的類實例,那麼直到第五個屬性值的 set函數被調用時,該類實例才具有完整連續的狀態。這也就意味著類的調用者可能會看到類實例的不連續狀態。

方案三: ☆☆☆☆☆

了解了以上兩種比較常見但是效果卻不太理想的方案後,正式引出第三種方案 —— 進化後的 Builder模式,既有以上兩種方案的優點,又摒棄它們的缺點。代碼如下:

public class User {
    private final String mName;     //必選
    private final String mGender;   //可選
    private final int mAge;         //可選
    private final String mPhone;    //可選

    public User(UserBuilder userBuilder) {
        this.mName = userBuilder.name;
        this.mGender = userBuilder.gender;
        this.mAge = userBuilder.age;
        this.mPhone = userBuilder.phone;
    }

    public String getName() {
        return mName;
    }

    public String getGender() {
        return mGender;
    }

    public int getAge() {
        return mAge;
    }

    public String getPhone() {
        return mPhone;
    }


    public static class UserBuilder{
        private final String name;     
        private String gender;   
        private int age;         
        private String phone;

        public UserBuilder(String name) {
            this.name = name;
        }

        public UserBuilder gender(String gender){
            this.gender = gender;
            return this;
        }

        public UserBuilder age(int age){
            this.age = age;
            return this;
        }

        public UserBuilder phone(String phone){
            this.phone = phone;
            return this;
        }

        public User build(){
            return new User(this);
        }   
    }


}

從以上代碼可以看出這幾點:

User類的構造函數是私有的,這意味著調用者不可直接實例化這個類。 User類是不可變的,其中必選的屬性值都是 final 的並且在構造函數中設置;同時對所有的屬性取消 setters函數,只保留 getter函數。 UserBuilder 的構造函數只接收必選的屬性值作為參數,並且只是將必選的屬性設置為 fianl,來保證它們在構造函數中設置。

接下來,User類的使用方法如下:

    public User getUser(){
        return new
                User.UserBuilder("gym")
                .gender("female")
                .age(20)
                .phone("12345678900")
                .build();
    }

以上通過 進化的Builder模式形象的體現在User的實例化。






三. AS 中自動生成 變化Builder模式

分析比較了以上三個方案後,也學習了解了 化Builder模式的好處和運用方法,可是你會發現它需要編寫很多樣板代碼,需要在內部類 UserBuilder 中重復外部類User的屬性定義。其實在AS中,可以通過安裝 InnerBuilder 的插件來簡化 Builder模式的創建過程,以下為安裝使用步驟:


1. 在File菜單下打開 settings 選項,點開Plugins。

這裡寫圖片描述


2. 在中間的輸入框輸入 Builder 點擊搜索,安裝後根據提示重開AS即可。

這裡寫圖片描述


3. 在編寫User類時,只需要把屬性名確定下來,然後鼠標右鍵打開Generate菜單,選擇 Builder按鈕,在彈出的Builder配置對話框中進行相關配置的勾選,如下:

這裡寫圖片描述


完成以上步驟後,即可自動生成 進化Builder模式 代碼,可能稍有不同,根據自身需求修改即可。






四. 開源函數庫的例子

正如開頭所說,Builder模式 被廣泛運用於Android中的各個領域,無論是Android SDK 或各種開元函數庫中,接下來關於Builder模式的運用舉幾個例子:


1. Android系統對話框 AlertDialog 的使用

    AlertDialog alertDialog = new AlertDialog.Builder(this).
            setTitle("標題").
            setMessage("內容").
            setIcon(R.drawable.ic_logo).
            create();
    alertDialog.show();

2.網絡請求框架 OkHttp 的請求封裝:

private Request(Builder builder){
    this.url = builder.url;
    this.method = builder.method ;
    this.headers = builder.headers.build() ;
    this.body = builder.body ;
    this.tag = builder.tag != null ? builder.tag : this;
}

3. 圖片緩存函數庫 Android-Universal-Image-Loader 的全局配置也運用到了,在此不再舉例了。


其實以上內容幾乎都是書上的,前幾天讀到了這一章內容,講的十分淺顯易懂,之前自己沒怎麼理解這塊內容,趁這次機會詳細學習了一遍,以上內容及代碼均手碼出來,包括安裝插件,親自動手實踐學習理解更深,在此謝過 顧浩鑫coder。

希望對你有幫助 :)

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved