設計模式-05建造者模式(Builder Pattern)
阿新 • • 發佈:2020-02-11
1.模式動機
比如我們要組裝一臺電腦,都知道電腦是由 CPU、主機板、記憶體、硬碟、顯示卡、機箱、顯示器、鍵盤和滑鼠組成,其中非常重要的一點就是這些硬體都是可以靈活選擇,但是組裝步驟都是大同小異(可以組一個高配置的,也可以組一個低配置的),這時建造者模式可以很好的描述這類產品的建立。
2.模式定義
建造者模式的定義:指將一個複雜物件的構造與它的表示分離,使同樣的構建過程可以建立不同的表示,這樣的設計模式被稱為建造者模式。
它是將一個複雜的物件分解為多個簡單的物件,然後一步一步構建而成。它將變與不變相分離,即產品的組成部分是不變的,但每一部分是可以靈活選擇的。
注意
建造者模式和工廠模式的關注點不同:建造者模式注重零部件的組裝過程,而工廠方法模式更注重零部件的建立過程,但兩者可以結合使用。
3.模式結構
建造者模式由產品、抽象建造者、具體建造者、指揮者等 4 個要素構成,現在我們來分析其基本結構和實現方法。
建造者模式的主要角色如下:
- 產品角色:它是包含多個組成部件的複雜物件,由具體建造者來建立其各個部件。
- 抽象建造者:它是一個包含建立產品各個子部件的抽象方法的介面,通常還包含一個返回複雜產品的方法
getResult()
。 - 具體建造者:實現抽象建造者介面,完成複雜產品的各個部件的具體建立方法。
- 指揮者:它呼叫建造者物件中的部件構造與裝配方法完成複雜物件的建立,在指揮者中不涉及具體產品的資訊。
4.模式程式碼
# 產品角色 @Getter @Setter @ToString public class Computer { private String cpu; private String ram; private String ssd; } # 抽象建造者 public abstract class AbstractComputerBuilder { protected Computer computer = new Computer(); public abstract void buildCPU(); public abstract void buildRAM(); public abstract void buildSSD(); public Computer getResult() { return computer; } } # 具體建造者 public class HighProfileComputerBuilder extends AbstractComputerBuilder { @Override public void buildCPU() { computer.setCpu("i9"); } @Override public void buildRAM() { computer.setRam("32G"); } @Override public void buildSSD() { computer.setSsd("1T"); } } # 指揮者 public class Director { private AbstractComputerBuilder builder; public Director(AbstractComputerBuilder builder) { this.builder = builder; } public Computer construct() { builder.buildCPU(); builder.buildRAM(); builder.buildSSD(); return builder.getResult(); } } # 客戶端呼叫 public class Client { public static void main(String[] args) { AbstractComputerBuilder builder = new HighProfileComputerBuilder(); Director director = new Director(builder); Computer highProfileComputer = director.construct(); System.out.println(highProfileComputer); // Computer(cpu=i9, ram=32G, ssd=1T) } }
我們也可以建造一個LowProfileComputerBuilder
,客戶端呼叫時建立低配置電腦建造者即可。
程式碼分析:
- 抽象建造者類中定義了產品的建立方法和返回方法
- 建造者模式的結構中還引入了一個指揮者類Director,該類的作用主要有兩個:一方面它隔離了客戶與生產過程;另一方面它負責控制產品的生成過程。指揮者針對抽象建造者程式設計,客戶端只需要知道具體建造者的型別,即可通過指揮者類呼叫建造者的相關方法,返回一個完整的產品物件
- 在客戶端程式碼中,無須關心產品物件的具體組裝過程,只需確定具體建造者的型別即可,建造者模式將複雜物件的構建與物件的表現分離開來,這樣使得同樣的構建過程可以創建出不同的表現。
5.總結
優點
- 在建造者模式中,客戶端不必知道產品內部組成的細節,將產品本身與產品的建立過程解耦,使得相同的建立過程可以建立不同的產品物件。
- 每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,使用者使用不同的具體建造者即可得到不同的產品物件。
- 可以更加精細地控制產品的建立過程。將複雜產品的建立步驟分解在不同的方法中,使得建立過程更加清晰,也更方便使用程式來控制建立過程。
- 增加新的具體建造者無須修改原有類庫的程式碼,指揮者類針對抽象建造者類程式設計,系統擴充套件方便,符合“開閉原則”。
缺點
- 建造者模式所建立的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用範圍受到一定的限制。
- 如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。
6.擴充套件:模式的簡化
我們可以使用 lombok 提供的 @Builder
註解實現簡單的建造者模式:
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@Builder
public class TV {
private String name;
private String address;
private Date createData;
}
編譯後的程式碼如下:
import java.util.Date;
public class TV {
private String name;
private String address;
private Date createData;
TV(String name, String address, Date createData) {
this.name = name;
this.address = address;
this.createData = createData;
}
public static TV.TVBuilder builder() {
return new TV.TVBuilder();
}
public String getName() {
return this.name;
}
public String getAddress() {
return this.address;
}
public Date getCreateData() {
return this.createData;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public void setCreateData(Date createData) {
this.createData = createData;
}
public String toString() {
return "TV(name=" + this.getName() + ", address=" + this.getAddress() + ", createData=" + this.getCreateData() + ")";
}
public static class TVBuilder {
private String name;
private String address;
private Date createData;
TVBuilder() {
}
public TV.TVBuilder name(String name) {
this.name = name;
return this;
}
public TV.TVBuilder address(String address) {
this.address = address;
return this;
}
public TV.TVBuilder createData(Date createData) {
this.createData = createData;
return this;
}
public TV build() {
return new TV(this.name, this.address, this.createData);
}
public String toString() {
return "TV.TVBuilder(name=" + this.name + ", address=" + this.address + ", createData=" + this.createData + ")";
}
}
}
呼叫者程式碼:
public class TVClient {
public static void main(String[] args) {
TV tv = TV.builder()
.name("長虹")
.address("中國")
.createData(new Date())
.build();
System.out.println(tv); // TV(name=長虹, address=中國, createData=Tue Feb 11 11:58:41 CST 2020)
}
}
正文中是標準的建造者模式,擴充套件中是簡單的建造者模式,按需選擇