設計模式,創建型模式之建造者模式

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:
UML for builder

首先,將類的構造函數私有化了,創建類只能通過Pizza.Builder來進行。而Pizza.Builder創建類的過程,其實是一個定製化類,逐步給類設置屬性的過程。通過鏈式調用,可以很容易並直觀地給類添加需要的屬性,可伸縮性很強。想要創建什麼類型的Pizza,完全由調用者來決定。

建造者模式非常的常見,
Calendar.Builder,提供了一種自定義構造Calendar的方式。
StringBuilder,可以動態,靈活地構造String對象。類似地還有MyBatisAbstractSQL,用直觀的方式,逐步地構造一個完整的SQL語句。

4 總結

當某個類有很多個屬性,或者屬性之間有多種組合(Calendar.Builder),又或者是對象維護了一個狀態,需要逐步地調用方法使得該狀態變得完整(StringBuilder),請考慮使用建造者模式

文中例子的github地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章