構(gòu)造者模式(Builder Pattern)主要用于復(fù)雜對(duì)象的構(gòu)建,將一個(gè)復(fù)雜對(duì)象的構(gòu)造過程和它的表現(xiàn)層分離開來。
直接擼個(gè)蓋房子的例子。
這里三個(gè)類:
BuildingDesign:房屋設(shè)計(jì)圖,包括一些房屋的屬性,比如寬、高、顏色。
House:最后要?jiǎng)?chuàng)建出實(shí)例的類。
HouseBuilder:房屋構(gòu)建者,可以理解為一個(gè)公司,或一群工人等等,總之用戶通過這個(gè)類去構(gòu)建House,而不是直接自己去創(chuàng)建House。
貼一下各類的實(shí)現(xiàn):
/**
* 房屋設(shè)計(jì)圖
*/
public class BuildingDesign {
private double width;
private int height;
private String color;
public BuildingDesign() {
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
/**
* 大House
*/
public class House {
private double width;
private int height;
private String color;
public House(BuildingDesign design) {
this.width = design.getWidth();
this.height = design.getHeight();
this.color = design.getColor();
}
@Override
public String toString() {
return "House{" +
"width=" + width +
", height=" + height +
", color='" + color + '\'' +
'}';
}
}
/**
* 構(gòu)建者
*/
public class HouseBuilder {
private BuildingDesign buildingDesign;
public HouseBuilder() {
buildingDesign = new BuildingDesign();
}
public void setWidth(double width) {
this.buildingDesign.setWidth(width);
}
public void setHeight(int height) {
this.buildingDesign.setHeight(10);
}
public void setColor(String color) {
this.buildingDesign.setColor(color);
}
public House build() {
if (buildingDesign == null){
return null;
}else {
return new House(buildingDesign);
}
}
}
使用:
public class Main {
public static void main(String[] args) {
HouseBuilder builder = new HouseBuilder();
builder.setWidth(130.00);
builder.setHeight(3);
builder.setColor("紅色");
House house = builder.build();
System.out.println(house);
}
}
運(yùn)行結(jié)果:
House{width=130.0, height=10, color='紅色'}
這樣就完成了構(gòu)建者模式,這里的好處:
- 在調(diào)用
builder.build();
之前,隨便房屋屬性并不會(huì)造成資源浪費(fèi),因?yàn)槎际窃趎ew對(duì)象之前。 - 屏蔽了房屋創(chuàng)建的復(fù)雜過程,這一點(diǎn)代碼里沒體現(xiàn)出來,房屋的構(gòu)造過程可能是很復(fù)雜的,但用戶只提供了寬、高、顏色,又或者是用戶根本沒有要求顏色,所以設(shè)計(jì)圖里,也就是
BuildingDesign
里要提供默認(rèn)值,所以代碼修改這樣:
/**
* 房屋設(shè)計(jì)圖
*/
public class BuildingDesign {
private double width = 2;
private int height = 100;
private String color = "白色";
...
}
這樣即使使用者不指定某些屬性,也會(huì)用默認(rèn)的創(chuàng)建出來,比如一些復(fù)雜的屬性,用戶可能大多數(shù)不需要設(shè)置,但是用戶想設(shè)置的時(shí)候必須可以設(shè)置。
為什么跟看到的一些構(gòu)建者不一樣?比如OkHttp里的OkHttpClient和Request的創(chuàng)建。
那些只是使用了鏈?zhǔn)降谋磉_(dá)方式,這里簡單數(shù)一下鏈?zhǔn)降乃枷耄瓷厦娴拇a:
HouseBuilder builder = new HouseBuilder();
builder.setWidth(130.00);
builder.setHeight(3);
builder.setColor("紅色");
builder.build();
比如builder是個(gè)包工頭,對(duì)應(yīng)上面5行代碼描述起來是這樣的:
1.“包工頭,過來一下”
2.“包工頭,我的房子要寬130”
3.“包工頭,我的房子要高3層”
4.“包工頭,我的房子要紅色”
5.“包工頭,開始蓋吧”
鏈?zhǔn)降臅鴮懛绞绞沁@樣的:
new HouseBuilder().setWidth(130.00).setHeight(3).setColor("紅色").build();
這意思就行,你把包工頭喊過來之后,他回說:“在你交代完成之前,我一直在,你不需要喊我,直接說你的需求”,描述起來:
“包工頭,過來一下,我的房子要寬130,高3層,紅色,開始蓋吧”
實(shí)現(xiàn)這種書寫方式也很簡單,設(shè)置完屬性把自己返回回去就好了,修改HouseBuilder
的setter方法:
/**
* 構(gòu)建者
*/
public class HouseBuilder {
...
public HouseBuilder setWidth(double width) {
this.buildingDesign.setWidth(width);
return this;
}
public HouseBuilder setHeight(int height) {
this.buildingDesign.setHeight(10);
return this;
}
public HouseBuilder setColor(String color) {
this.buildingDesign.setColor(color);
return this;
}
...
}
代碼完成,一般還會(huì)把Builder設(shè)置成內(nèi)部類,都一個(gè)意思,隨便怎么搞。
非常的絲滑:
System.out.println( new HouseBuilder().setWidth(130.00).setHeight(3).setColor("紅色").build());
System.out.println( new HouseBuilder().setHeight(3).setColor("紅色").build());
System.out.println( new HouseBuilder().setColor("紅色").build());
System.out.println( new HouseBuilder().build());
House{width=130.0, height=10, color='紅色'}
House{width=2.0, height=10, color='紅色'}
House{width=2.0, height=100, color='紅色'}
House{width=2.0, height=100, color='白色'}
隨便設(shè)置什么屬性,或者不設(shè)置,蓋住來的房子都可以住。