Builder(建造者)設(shè)計模式的定義
將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
使用套路
- 靜態(tài)內(nèi)部類使用鏈式調(diào)用的方式來設(shè)置類的表現(xiàn)形式
- 私有外部類的構(gòu)造方法,通過靜態(tài)內(nèi)部來獲取參數(shù)進行表現(xiàn)
強調(diào)
-
鏈式調(diào)用并不是Builder設(shè)計模式,只是一種手法,來提高編碼速度和代碼可讀性,如:RxJava 將鏈式編程用到的極致。想必有一些人會把 鏈式調(diào)用 與 Builder設(shè)計模式 混為一談。
Flowable.just("Hello world") .subscribe(new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } });
類圖

Buidler設(shè)計模式類圖.png
- Director: 統(tǒng)一組裝的過程
- Builder: 抽象的Builder類
- ConcreateBuilder: 具體的Builder類
- Product: 產(chǎn)品的抽象類
上面描述的是經(jīng)典的Builder設(shè)計模式的類圖,但是我們在實際使用過程中為了避免產(chǎn)生多余的對象,消耗多余的內(nèi)存,Direcotr 通常是被省略掉。而是通過 Builder 來進行組裝,并且通過鏈式調(diào)用來設(shè)置參數(shù)。
示例代碼
示例1
public class Human {
private final String mNo;
private final String mName;
private final int mAge;
private Human(Builder builder) {
this.mNo = builder.no;
this.mName = builder.name;
this.mAge = builder.age;
}
public int getAge() {
return mAge;
}
public String getName() {
return mName;
}
public String getNo() {
return mNo;
}
public static class Builder {
private final String no;
private String name;
private int age;
public Builder(String no) {
this.no = no;
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
public Human build() {
return new Human(this);
}
}
}
調(diào)用
Human human = new Human.Builder("123456")
.setName("lisi")
.setAge(20)
.build();
上面一段代碼是一個基本的 Builder設(shè)計模式的代碼。通過實例化 Human 中的 Builder 對象來設(shè)置屬性,最后我們在調(diào)用 build() 方法實例化 Human 對象。而且我們可以在 build() 中進行一些判空和數(shù)據(jù)初始化。
public Human build() {
if (TextUtils.isEmpty(name)) {
name = "未知";
}
return new Human(this);
}
示例2
之前在Logger源碼分析理解時,它的 PrettyFormatStrategy 和 CsvFormatStrategy 均使用了 Builder設(shè)計模式,但是與 示例1 稍有些不同。
public class Human {
private final String mNo;
private final String mName;
private final int mAge;
private Human(Builder builder) {
this.mNo = builder.no;
this.mName = builder.name;
this.mAge = builder.age;
}
public static Builder newBuilder(String no) {
return new Builder(no);
}
public int getAge() {
return mAge;
}
public String getName() {
return mName;
}
public String getNo() {
return mNo;
}
public static class Builder {
private final String no;
private String name;
private int age;
private Builder(String no) {
this.no = no;
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
public Human build() {
if (TextUtils.isEmpty(name)) {
name = "未知";
}
return new Human(this);
}
}
}
調(diào)用
Human human = Human.newBuilder("123456")
.setName("lisi")
.setAge(20)
.build();
總結(jié)
- Builder 在很多系統(tǒng)框架以及第三框架中都有使用,如:AlertDialog,OkHttp等,可以通過理解它們的源碼進行更深的學(xué)習(xí)
- 如果類中有很多參數(shù),并且有很多參數(shù)都是有默認值的時候就可以使用 Buidler設(shè)計模式