《一天一模式》— 建造者模式

1、建造者模式的概念

建造者模式(Builder Pattern)使用多個簡單的對象一步一步構建成一個複雜的對象。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。 java

2、何時使用建造者模式

簡單來講,建造者模式經過一步步的設置(構建)對象的值,最終構建了一個對象。設計模式

經常使用場景以下:數組

  • 經過步驟來建立對象,一步步將多個值裝配到一個對象中;
  • 靈活配置類的數據,可自定義順序;
  • 初始化一個對象時,參數過多,不方便用構造函數,可讀性差;
  • 初始化一個對象時,參數組合靈活,不方便用構造函數;

3、怎麼使用建造者模式

3.1 不適用建造者模式的弊端

好比一個對象的參數過多,經過構造函數來建立,很是繁瑣切可讀性差,例以下面的僞代碼:併發

public class Obj {

    public Obj(10個參數) { ... }

}

// 使用
Obj obj = new Obj(1,2,3,4,5,6,7,8,9,10);

寫起來麻煩,讀起來不清晰,要記得第幾個參數表明那個字段,通常超過3個參數就不太好記了。ide

此外,Sonarlint等代碼質量檢測工具也會把這種長參數的構造函數定義爲壞味道。函數

還有,就是構件對象特別靈活,例以下面僞代碼:工具

public class Obj {
    
    public Obj(int a, int b) { ... }

    public Obj(int a, float c) { ... }

    public Obj(int b, double d) { ... }

    ....

}

這種不一樣參數列表的構造函數,寫起來也很複雜,讀起來很困難。以上的狀況均可以用建造者模式去解決。ui

3.2 建造者模式的實現方式

定義一個可使用建造者模式的需求,而後用Java語言來實現。this

例如,要開發一個表明Http返回值的業務對象,這個對象須要4個屬性:spa

  • 業務狀態碼:code;
  • 業務狀態碼描述:desc;
  • 返回消息:msg;
  • 返回數據:data;

每次返回時,要求code和desc是必填項,msg和data爲選填項(可都不返回,可只返回一個,或者返回兩個)。

下面用建造者模式來建立這個對象:

代碼以下:

public class HttpResult<T> {

    /**
     * 構造函數。
     */
    private HttpResult() {
    }

    /**
     * 構造函數。
     *
     * @param builder 建造者。
     */
    private HttpResult(Builder<T> builder) {
        this.code = builder.status.getCode();
        this.desc = builder.status.getDesc();
        this.msg = builder.msg;
        this.data = builder.data;
    }

    /**
     * @return 得到返回代碼值。
     */
    public int getCode() {
        return code;
    }

    /**
     * @return 得到返回代碼描述。
     */
    public String getDesc() {
        return desc;
    }

    /**
     * @return 得到響應消息。
     */
    public String getMsg() {
        return msg;
    }

    /**
     * @return 得到響應數據。
     */
    public T getData() {
        return data;
    }

    /**
     * @return 重寫toString()方法。
     */
    @Override
    public String toString() {
        return "HttpResult{" +
                "code=" + code +
                ", desc='" + desc + '\'' +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }

    /**
     * HttpResult的構造器。
     *
     * @author xuepeng
     */

    public static class Builder<K> {

        /**
         * 構造函數。
         *
         * @param status 返回狀態。
         */
        public Builder(HttpResultStatus status) {
            this.status = status;
        }

        /**
         * 設置返回消息。
         *
         * @param msg 返回消息。
         * @return HttpResult.Builder對象。
         */
        public Builder<K> msg(String msg) {
            this.msg = msg;
            return this;
        }

        /**
         * 設置返回數據。
         *
         * @param data 返回數據。
         * @return HttpResult.Builder對象。
         */
        public Builder<K> data(K data) {
            this.data = data;
            return this;
        }

        /**
         * 建立HttpResultEntity對象。
         *
         * @return HttpResultEntity對象。
         */
        public HttpResult<K> build() {
            return new HttpResult<>(this);
        }

        /**
         * @return 重寫toString()方法。
         */
        @Override
        public String toString() {
            return "Builder{" +
                    "status=" + status +
                    ", msg='" + msg + '\'' +
                    ", data=" + data +
                    '}';
        }

        /**
         * 返回狀態。
         */
        private HttpResultStatus status;
        /**
         * 返回消息。
         */
        private String msg;
        /**
         * 返回數據。
         */
        private K data;

    }

    /**
     * 返回代碼值。
     */
    private int code;
    /**
     * 返回代碼描述。
     */
    private String desc;
    /**
     * 返回消息。
     */
    private String msg = StringUtils.EMPTY;
    /**
     * 返回數據。
     */
    private T data;

}

上面類就是一個HttpResult的對象,經過建造者模式去建立,主要作了以下事情:

  • 屏蔽了public的構造函數;
  • 定義了一個private的構造函數,便於給內部的建造者調用,入參是建造者對象(也就是說,在建造者構件完畢後,會new一個HttpResult,併發建造者本身傳遞給HttpResult,HttpResult取建造者中的數據初始化本身的字段);
  • 定義了一個內部靜態類Builder,構造函數是需求中說的返回碼(必填項);
  • 定義了幾個鏈式調用的方法,msg和data,能夠隨意設置(選填項);
  • 定義了一個build方法,在設置好數據後在調用該方法,方法調用HttpResult的private的構造函數,建立對象;

上面就是建造者模式的幾個核心點,建造者模式的使用方式以下:

// 填寫所有參數
public static <T> HttpResult<T> success(String msg, T data) {
        return new HttpResult.Builder<T>(SUCCESS)
                             .msg(msg)
                             .data(data)
                             .build();
}

// 填寫1個可選參數
public static <T> HttpResult<T> success(String msg, T data) {
        return new HttpResult.Builder<T>(SUCCESS)
                             .msg(msg)
                             .build();
}

// 不填寫可選參數
public static <T> HttpResult<T> success(String msg, T data) {
        return new HttpResult.Builder<T>(SUCCESS).build();
}
  • 經過new一個HttpResult.Builder來建立一個建造者,構造函數是返回碼(code, desc,這裏作成了一個枚舉對象);
  • 而後能夠選擇性的調用msg()或者data()去設置HttpResult的可選字段;
  • 最後,調用build()來建造一個HttpResult;

4、總結

建造者模式的好處:

  • 可讀性高:解決了構造函數參與列表過長的問題,並經過鏈式調用方式來建造對象,代碼可讀性高;
  • 擴展性強:當有新的參數須要設置時,只添加方法便可豐富鏈式調用的設置方法;

建造者模式與其餘用來建立對象的設計模式的不一樣點在於,它關注的是經過一步步的構建來建立一個對象,且對象的步驟能夠隨意改變

以上就是我對建造者模式的一些理解,有不足之處請你們指出,謝謝。

相關文章
相關標籤/搜索