編輯:關於Android編程
Builder模式是一種設計模式,最初被介紹於《設計模式:可復用面向對象軟件的基礎》,目前在Java及Android中用處更是十分廣泛,因此基本的了解與學習應當掌握。
首先從它的定義開始介紹:
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模式,基於定義的介紹。這種基本模式重點在於:抽象出對象創建的步驟,並通過調用不同的具體實現從而得到不同的結果。 但是在實際運用中並非是以上形式,而是進化成另一種體現形式,目的在於 減少對象創建過程中引入的多個重載構造函數、可選參數以及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的實例化。
分析比較了以上三個方案後,也學習了解了 化Builder模式的好處和運用方法,可是你會發現它需要編寫很多樣板代碼,需要在內部類 UserBuilder 中重復外部類User的屬性定義。其實在AS中,可以通過安裝 InnerBuilder 的插件來簡化 Builder模式的創建過程,以下為安裝使用步驟:



完成以上步驟後,即可自動生成 進化Builder模式 代碼,可能稍有不同,根據自身需求修改即可。
正如開頭所說,Builder模式 被廣泛運用於Android中的各個領域,無論是Android SDK 或各種開元函數庫中,接下來關於Builder模式的運用舉幾個例子:
AlertDialog alertDialog = new AlertDialog.Builder(this).
setTitle("標題").
setMessage("內容").
setIcon(R.drawable.ic_logo).
create();
alertDialog.show();
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;
}
其實以上內容幾乎都是書上的,前幾天讀到了這一章內容,講的十分淺顯易懂,之前自己沒怎麼理解這塊內容,趁這次機會詳細學習了一遍,以上內容及代碼均手碼出來,包括安裝插件,親自動手實踐學習理解更深,在此謝過 顧浩鑫coder。
希望對你有幫助 :)
Google推薦的圖片加載庫Glide介紹
在泰國舉行的谷歌開發者論壇上,谷歌為我們介紹了一個名叫Glide的圖片加載庫,作者是bumptech。這個庫被廣泛的運用在google的開源項目中,包括2014年goog
Android Listview點贊問題關於圖片重復問題
《最近做一個小功能遇到這麼一個問題,listview 與 baseadapter結合使用,關於點贊的的時候 圖片重復問題,比如:我在第1個item 點贊然後 心型換成了紅
Android中SparseArray性能優化的使用方法
之前一篇文章研究完橫向二級菜單,發現其中使用了SparseArray去替換HashMap的使用.於是乎自己查了一些相關資料,自己同時對性能進行了一些測試。首先先說一下Sp
Android自定義視頻播放器(網絡/本地)
最近因公司項目要求需要寫一個播放器,自帶的又不太好用,也不太好看。自能自定義啦。查看了很多資料,都沒有完善的,還好得以為前輩的指點得以完成,感謝Yang。本篇裡面我有可能