簡介
概念
建造者設計模式(Builder Design Pattern)又叫作生成器模式,是一種物件構建模式,其核心在于將產品和產品建造程序解耦,
建設者模式允許用戶只通過指定復雜物件的型別和內容就可以一步一步地構建出一個復雜的物件,在這個程序當中,用戶不需要知道內部的具體構建細節,
因此,建造者模式特別適合用于構建具有復雜內部結構的物件,或者是需要生成內部本身相互依賴的物件,
與工廠模式的區別
工廠模式注重的是整體物件的創建方法,而建造者模式注重的是物件的創建程序,創建物件的程序方法可以在創建時自由呼叫,
它們的區別還可以使用以下的經典例子解釋:
顧客走進一家餐廳點餐,根據用戶不同的選擇,可以利用工廠模式來制作不同的食物,比如披薩、漢堡、沙拉,對于披薩來說,用戶又有各種配料可以定制,比如奶酪、西紅柿、起司,可以通過建造者模式根據用戶選擇的不同配料來制作披薩,
實作方式
傳統的建造者模式會包括以下 4 部分:
- 建造者 Builder 抽象類:構建物件的抽象類,包括
buildPartX()相關的構建物件方法,以及getResult()這樣獲取實際物件的方法 - 建造者 ConcreteBuilder 具體類:繼承自 Builder 抽象類,完善及構建自己特殊的
buildPartX()方法 - 指揮者 Director 具體類:與客戶端對接,然后根據需要創建出所需的物件,可以看做是一個代理
- 產品 Product 具體類:實際被構建出來的實際產品類
簡單的 Builder 抽象類代碼示例如下:
public abstract class Builder {
abstract void buildPartA();
abstract void buildPartB();
abstract Product createProduct();
}
具體的 ConcreteBuilder 類代碼示例如下:
public class ConcreteBuilder extends Builder {
private Product product = new Product();
public void buildPartA() {
product.setPartA("A");
}
public void buildPartB() {
product.setPartB("B");
}
public Product createProduct() {
return product;
}
}
產品 Product 類代碼示例如下:
public class Product {
private String partA;
private String partB;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
}
指揮者 Director 類代碼示例如下:
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public Product getProductA() {
builder.buildPartA();
return builder.createProduct();
}
public Product getProductB() {
builder.buildPartB();
return builder.createProduct();
}
}
具體實作
傳統的建造者模式所需的部分較多,在實際開發程序中,是需要簡化系統結構,減少程式當中類的個數,并且降低用戶的使用成本,
另一個常見的使用方式是,通過直接將 Builder 類作為產品類的靜態內部類,這種方式更多的是降低較多成員變數時構建物件的復雜度,
以下是創建 ResourcePoolConfig 類的建造者模式代碼示例:
public class ResourcePoolConfig {
private String name;
private int maxTotal;
private int maxIdle;
private int minIdle;
private ResourcePoolConfig(Builder builder) {
this.name = builder.name;
this.maxTotal = builder.maxTotal;
this.maxIdle = builder.maxIdle;
this.minIdle = builder.minIdle;
}
// 將 Builder 類設計成了 ResourcePoolConfig 的內部類
// 也可以將 Builder 類設計成獨立的 ResourcePoolConfigBuilder 非內部類
public static class Builder {
private static final int DEFAULT_MAX_TOTAL = 8;
private static final int DEFAULT_MAX_IDLE = 8;
private static final int DEFAULT_MIN_IDLE = 0;
private String name;
private int maxTotal = DEFAULT_MAX_TOTAL;
private int maxIdle = DEFAULT_MAX_IDLE;
private int minIdle = DEFAULT_MIN_IDLE;
public ResourcePoolConfig build() {
// 校驗邏輯放到這里來做,包括必填項校驗、依賴關系校驗、約束條件校驗等
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("...");
}
if (maxIdle > maxTotal) {
throw new IllegalArgumentException("...");
}
if (minIdle > maxTotal || minIdle > maxIdle) {
throw new IllegalArgumentException("...");
}
return new ResourcePoolConfig(this);
}
public Builder setName(String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("...");
}
this.name = name;
return this;
}
public Builder setMaxTotal(int maxTotal) {
if (maxTotal <= 0) {
throw new IllegalArgumentException("...");
}
this.maxTotal = maxTotal;
return this;
}
public Builder setMaxIdle(int maxIdle) {
if (maxIdle < 0) {
throw new IllegalArgumentException("...");
}
this.maxIdle = maxIdle;
return this;
}
public Builder setMinIdle(int minIdle) {
if (minIdle < 0) {
throw new IllegalArgumentException("...");
}
this.minIdle = minIdle;
return this;
}
}
}
以下是 ResourcePoolConfig 類建造者模式的使用方式:
ResourcePoolConfig config = new ResourcePoolConfig.Builder()
.setName("dbconnectionpool")
.setMaxTotal(16)
.setMaxIdle(10)
.setMinIdle(6)
.build();
上述的示例代碼只是傳入 4 個引數,就可以看得出構建一個物件的復雜性了,如果所需構建引數的數量更多,使用建造者模式的優勢將會更加明顯,傳遞引數更加靈活,代碼具有更高的可讀性,
總結
優點
建造者模式的主要優點如下:
- 使用建造者模式可以使客戶端不必知道產品內部組成的細節
- 具體的建造者類之間是相互獨立的,這有利于系統的擴展
- 具體的建造者相互獨立,因此可以對建造的程序逐步細化,而不會對其他模塊產生任何影響
缺點
建造者模式的主要缺點如下:
- 建造者模式所創建的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式
- 如果產品的內部變化復雜,可能會導致需要定義很多具體建造者類來實作這種變化,導致系統變得很龐大,增加系統的理解難度和運行成本
適用場景
建造者模式的適用場景如下:
- 類的內部非常復雜,包含多個成員變數
- 類的屬性之間有一定的依賴關系或者約束條件,需要指定其生成順序
- 希望創建的物件是不可變的,在物件創建之后不能修改物件內部的屬性值,暴露 setter 方法的創建物件方式就不適用了
原始碼
在 JDK 中,java.lang.StringBuilder 是經典的建造者模式,
其中具體的如 append()、delete()、reverse() 等方法都是直接回傳當前 StringBuilder 物件,其可以再繼續調動類似的方法以構建出一個想要的 StringBuilder 物件,
如下是使用 StringBuilder 的一個代碼示例:
StringBuilder stringBuilder = new StringBuilder()
.append("olleH")
.delete(0, 1)
.insert(0, "o")
.reverse();
// Hello
System.out.println(stringBuilder);
首發于翔仔的個人博客,點擊查看更多,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/503337.html
標籤:其他
上一篇:設計模式之(4)——單例模式
