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的插件。
編寫User類代碼的時候,只需要把屬性名確定下來,然後單擊鼠標右鍵,打開Generate菜單,選擇Builder按鈕,在配置對話框中進行相關配置的勾選即可。
舉個例子
public class Person {
private final String mLastName;//必填
private final String mFirstName;//必填
private int mHeight;//選填
private int mBodyWeight;//選填
}
第一個打勾的意思是:生成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:
所以,這都體現出Builder設計模式的好處:
將一個複雜對象與它的表示分離,使得同樣的構建過程可以創建不同的表示。
減少對象創建過程中引入多個重載構造函數,可選參數以及setters函數過度使用導致的不必要的複雜性。
參考:《Android高級進階》