1. 程式人生 > >Android設計模式之Builder模式

Android設計模式之Builder模式

Builder設計模式

定義:

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

參與者:

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

Builder模式的變種

目的:

減少物件建立過程中引入多個過載建構函式,可選引數以及setters函式過度使用導致的不必要的複雜性。

例子講解:

public class User {
    private final String mFirstName;//必選
    private final String mLastName;//必選
    private final String mGender;//可選屬性
    private final int mAge;//可選屬性
    private final String mPhoneNo;//可選屬性

    private User(UserBuilder userBuilder) {
        mFirstName = userBuilder.firstName;
mLastName = userBuilder.lastName; mGender = userBuilder.gender; mAge = userBuilder.age; mPhoneNo = userBuilder.phoneNo; } public String getmFirstName() { return mFirstName; } public String getmLastName() { return mLastName; } public
String getmGender() { return mGender; } public int getmAge() { return mAge; } public String getmPhoneNo() { return mPhoneNo; } public static class UserBuilder{ private final String firstName; private final String lastName; private String gender; private int age; private String phoneNo; public UserBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public UserBuilder gender(String gender) { this.gender = gender; return this; } public UserBuilder age(int age) { this.age = age; return this; } public UserBuilder phoneNo(String phoneNo) { this.phoneNo = phoneNo; return this; } public User build() { return new User(this); } } } //使用 //這樣子就構建了一個User物件,當然,後面的屬性也可以選填或者不填。 User user = new User.UserBuilder("黃","小明").age(15).gender("qqq").phoneNo("456789").build();

優點

  • 減少物件建立過程中引入多個過載建構函式,可選引數以及setters函式過度使用導致的不必要的複雜性。
  • 程式碼容易維護,容易使用。後續想要新增屬性,直接新增一個相對應的屬性和其方法即可。
  • 如果採取無參建構函式,接著使用set來設定屬性,那麼User類的例項狀態不連續。直到第五個set函式被呼叫時,該類的例項才具有完整連續的狀態,也就意味著類呼叫者會看到該類例項的不連續狀態。
  • 設定final修飾屬性值不可變。

缺點

  • 需要編寫很多的樣板程式碼,需要在內部類UserBuilder中重複外部類User的屬性定義。

變種Builder模式的自動化生成

在AndroidStudio中,安裝名為InnerBuilder的外掛。
InnerBuilder

編寫User類程式碼的時候,只需要把屬性名確定下來,然後單擊滑鼠右鍵,開啟Generate選單,選擇Builder按鈕,在配置對話方塊中進行相關配置的勾選即可。

舉個例子


public class Person {
    private final String mLastName;//必填
    private final String mFirstName;//必填
    private int mHeight;//選填
    private int mBodyWeight;//選填
}

CreateBuilder

第一個打勾的意思是:生成final欄位的構造器方法。
如果不打勾,那麼生成的程式碼就和我們上面的User類程式碼一致。

生成後的程式碼:


public class Person {
    private final String mLastName;//必填
    private final String mFirstName;//必填
    private int mHeight;//選填
    private int mBodyWeight;//選填

    private Person(Builder builder) {
        mLastName = builder.mLastName;
        mFirstName = builder.mFirstName;
        mHeight = builder.mHeight;
        mBodyWeight = builder.mBodyWeight;
    }

    public static final class Builder {
        private String mLastName;
        private String mFirstName;
        private int mHeight;
        private int mBodyWeight;

        public Builder() {
        }

        public Builder mLastName(String val) {
            mLastName = val;
            return this;
        }

        public Builder mFirstName(String val) {
            mFirstName = val;
            return this;
        }

        public Builder mHeight(int val) {
            mHeight = val;
            return this;
        }

        public Builder mBodyWeight(int val) {
            mBodyWeight = val;
            return this;
        }

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

利用工具來進行類的Builder模式構建真的很快,效率是槓槓的。

變種Builder模式的應用

1. Android系統對話方塊AlertDialog的使用

AlertDialog alertDialog = new AlertDialog.Builder(this)
                .setTitle("對話方塊標題")
                .setMessage("對話方塊內容")
                .setIcon(R.drawable.ic_launcher_background)
                .create();
        alertDialog.show();

2. 網路請求框架OkHttp的請求封裝

這個大家可以閱讀下OkHttp3的原始碼,裡面大量應用了Builder設計模式。
Request:
在這裡插入圖片描述
在這裡插入圖片描述

OkHttpClient:
666

所以,這都體現出Builder設計模式的好處:
將一個複雜物件與它的表示分離,使得同樣的構建過程可以建立不同的表示。
減少物件建立過程中引入多個過載建構函式,可選引數以及setters函式過度使用導致的不必要的複雜性。

參考:《Android高階進階》