前言
建造者模式即BUilder模式,看名字就可知是一種創建型模式。主要是解決
- 構造方法中參數過多導致的可讀性較差的問題;
- 在初始化時不必將所有參數進行設置的情況(通常有默認值)。
文中會舉例進行演示,通過例子能夠有一個更清晰的認識。
場景描述
許多游戲在進入游戲時,第一步往往是讓我們選擇角色的外形,如眼睛顏色,眼睛大小,發型,頭發顏色,臉型等等。假設現在要創建一個小明,大眼,綠色的瞳孔,中分頭,紅色頭發,鞋拔子臉。當然還有必填的姓名。
首先,我們創建一個Person的類,并改寫toString方法便于測試。
public class Person {
private String name;//姓名必填
private String eyeSize;//眼睛大小
private String eyeColor;//眼睛顏色
private String hairStyle;//發型
private String hairColor;//頭發顏色
private String face;//臉型
public Person(String name, String eyeSize, String eyeColor, String hairStyle, String hairColor, String face) {
this.name = name;
this.eyeSize = eyeSize;
this.eyeColor = eyeColor;
this.hairStyle = hairStyle;
this.hairColor = hairColor;
this.face = face;
}
@Override
public String toString() {
String s = "姓名:" + name + "\n"
+ "眼睛:" + eyeSize + "\n"
+ "眼睛顏色:" + eyeColor + "\n"
+ "發型:" + hairStyle + "\n"
+ "頭發顏色:" + hairColor + "\n"
+ "臉型:" + face;
return s;
}
}
同時我們編寫測試類,創建小明這個角色。在創建時我郁悶了,在通過構造方法對對象進行初始化時,我忘記了參數的順序。雖然現在IDE都非常的智能,會對參數進行提示,但是還是影響了我的開發效率。
最后我們艱辛的創建完了這個簡單的測試類
public static void main(String[] args) {
Person xiaoming = new Person("小明","大", "綠色", "中分", "紅色", "鞋拔子臉");
System.out.println(xiaoming.toString());
}
輸入結果如下:
姓名:小明
眼睛:大
眼睛顏色:綠色
發型:中分
頭發顏色:紅色
臉型:鞋拔子臉
老鐵,沒毛病。但是現在是只有6個參數的情況下,似乎還可以接受,但是如果再多幾個,orz!!
使用Builder模式
首先來說說使用Builder模式有什么優點:
- 默認參數,無需對所有參數進行初始化;
- 將實現變成鏈式調用,增加了代碼可讀性。
現在不管角色的外形,我只想創建一個小明的對象,來看看Builder模式會怎么做:
public static void main(String[] args) {
Person xiaoming = new Person.Builder("小明").create();
System.out.println(xiaoming.toString());
}
圖片.png
Are you kidding?就傳了個必填項姓名就創建好了?僅用一行代碼就創建好了這個對象。
在前言中講到過一點,設置默認值。以上實現就是基于默認值的設置。
接下來就來到了緊張刺激的代碼實現環節。Builder的實現
public class Person {
private String name;//姓名必填
//省略其他可選參數
private Person(Builder builder) { //1............
initialize(builder);
}
private void initialize(final Builder builder) {
name = builder.name;
//省略
}
public static class Builder {
//2..........
private String name;//姓名必填
private String eyeSize = "大";//眼睛大小
//省略
public Builder(String name) {
this.name = name;
}
public Builder setEyeSize(String eyeSize) {
this.eyeSize = eyeSize;
//3..........
return this;
}
//省略
//4..........
public Person create() {
return new Person(this);
}
}
@Override
public String toString() {
String s = "姓名:" + name + "\n"
+ "眼睛:" + eyeSize + "\n"
+ "眼睛顏色:" + eyeColor + "\n"
+ "發型:" + hairStyle + "\n"
+ "頭發顏色:" + hairColor + "\n"
+ "臉型:" + face;
return s;
}
}
劃一下重點:
- 因為我們要用過Builder來創建對象,所有需將Person類的構造方法私有化,且通過Builder來構建;
- 在Builder中初始化變量,對外部提供set方法;
- 實現鏈式的關鍵 return this;
- 設置完參數之后通過Person類的構造進行構建并返回實例對象。
繼續創建一個好看點的小紅:
Person xiaohong = new Person.Builder("小紅")
.setEyeColor("藍色")
.setEyeSize("大")
.setFace("鵝蛋臉")
.setHairStyle("大波浪")
.setHairColor("褐色")
.create();
是不是格外的清晰。
總結
將代碼寫成鏈式是非常優美的事情,像在Android開發中,我們可以將TitleBar的設置寫成鏈式,也可以將RecyclerView的初始化過程寫成鏈式;
看過dagger2生成的代碼就可以看出,文中builder模式是仿造它的實現,要是沒看過現在也可以轉去看,相信會輕松許多;
完整代碼移步gayhub。