1 概述
前面我們說了工廠模式和抽象工廠模式,下面來說說建造者模式。
建造者模式也是一種極爲常見的創建型模式,前面提到的兩類工廠模式隱藏了類的屬性與構造細節,而建造者模式通過Builder
類,適當地暴露了類的屬性,使得類的創建更具有靈活性和可讀性。
2 建造者模式
當一個類的構造函數包含很多參數,或者參數之間有很多種組合(如肯德基的套餐),調用構造函數來創建類將會變得不方便,可讀性也很差。對於多種組合的情況,工廠模式也將變得不適用。
在這種情況下,建造者模式提供了一種思路,通過將類的創建委託給建造器(Builder),將類的創建與表示分離,大大地簡化了類創建的複雜度。
3 案例
考慮做一個Pizza
,爲方便起見,讓它只包含尺寸,底,餡以及是否加芝士四個屬性。看看如何用建造者模式來創建:
public class Test {
public static void main(String[] args) {
Pizza.Builder pizzaBuilder = new Pizza.Builder();
Pizza pizza = pizzaBuilder.size(6)
.crustType(Pizza.CrustType.THIN)
.topping("Durian")
.build();
pizza.info();
}
}
public class Pizza {
private int size;// inch
private CrustType crustType;
private String topping;
private boolean cheese;// optional
private Pizza(Builder builder) {
if (builder.size <= 0) {
throw new IllegalStateException("Invalid pizza size.");
}
if (builder.crustType == null) {
throw new IllegalStateException("Invalid pizza crust type.");
}
if (builder.topping == null) {
throw new IllegalStateException("Invalid pizza topping.");
}
this.size = builder.size;
this.crustType = builder.crustType;
this.topping = builder.topping;
this.cheese = builder.cheese;
}
public void info() {
System.out.println("Pizza size: " + size + ", crust type: " + crustType + ", topping: " + topping + ", with cheese: " + cheese);
}
public static enum CrustType {
THIN, THICK
}
// inner class to build Pizza
public static class Builder {
private int size;
private CrustType crustType;
private String topping;
private boolean cheese = false;
public Builder size(int size) {
this.size = size;
return this;
}
public Builder crustType(CrustType crustType) {
this.crustType = crustType;
return this;
}
public Builder topping(String topping) {
this.topping = topping;
return this;
}
public Builder cheese(boolean cheese) {
this.cheese = cheese;
return this;
}
public Pizza build() {
return new Pizza(this);
}
}
}
輸出:
Pizza size: 6, crust type: THIN, topping: Durian, with cheese: false
UML:
首先,將類的構造函數私有化了,創建類只能通過Pizza.Builder
來進行。而Pizza.Builder
創建類的過程,其實是一個定製化類,逐步給類設置屬性的過程。通過鏈式調用,可以很容易並直觀地給類添加需要的屬性,可伸縮性很強。想要創建什麼類型的Pizza
,完全由調用者來決定。
建造者模式非常的常見,
如Calendar.Builder,提供了一種自定義構造Calendar
的方式。
如StringBuilder,可以動態,靈活地構造String
對象。類似地還有MyBatis
的AbstractSQL,用直觀的方式,逐步地構造一個完整的SQL
語句。
4 總結
當某個類有很多個屬性,或者屬性之間有多種組合(Calendar.Builder
),又或者是對象維護了一個狀態,需要逐步地調用方法使得該狀態變得完整(StringBuilder
),請考慮使用建造者模式。