設(shè)計模式 - Builder 模式

Effective Java 第2條:遇到多個構(gòu)造器參數(shù)時要考慮使用構(gòu)建器

三種創(chuàng)建對象的方式。

目錄

  • 重疊構(gòu)造器
  • JavaBeans
  • 構(gòu)建器 Builder

#重疊構(gòu)造器

/**
 * Create By IntelliJ IDEA.
 *
 * @Author: Cheng
 * @Date: 2017/10/30
 * @Time: 19:21
 * <p>
 * 層疊構(gòu)造器
 */
public class User {
    private String name;        // required
    private String password;    // required

    private int id;             // optional
    private String email;       // optional
    private String phone;       // optional
    private String address;     // optional

    public User(String name, String password, int id, String email, String phone, String address) {
        this.name = name;
        this.password = password;
        this.id = id;
        this.email = email;
        this.phone = phone;
        this.address = address;
    }

    public User(String name, String password) {
        this(name, password, -1, null, null, null);
    }
    
    public User(String name, String password, int id) {
        this(name, password, id, null, null, null);
    }

    public User(String name, String password, int id, String email) {
        this(name, password, id, email, null, null);
    }
    
    public User(String name, String password, int id, String email, String phone) {
        this(name, password, id, email, phone, null);
    }

    // 不提供 setter 方法,該對象就是不可變的了。
}

提供第一個只有必要參數(shù)的構(gòu)造器,第二個構(gòu)造器有一個可選參數(shù),第三個有兩個可選參數(shù),依次類推,最后一個構(gòu)造器包含所有可選參數(shù)。

重疊構(gòu)造器模式可行,但是當有許多參數(shù)的時候,客戶端代碼會很難編寫,并且依然較難閱讀。

參數(shù)一多起來不閱讀文檔將很難理解創(chuàng)建對象該傳什么參數(shù) 或者將參數(shù)順序搞亂


#JavaBeans

/**
 * Create By IntelliJ IDEA.
 *
 * @Author: Cheng
 * @Date: 2017/10/30
 * @Time: 19:21
 * <p>
 * JavaBeans
 */
public class User {
    private String name;        // required
    private String password;    // required

    private int id;             // optional
    private String email;       // optional
    private String phone;       // optional
    private String address;     // optional

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    // 省略getter and setter方法。
}

JavaBeans模式彌補了重疊構(gòu)造器的不足。說的明白點,就是創(chuàng)建實例很容易,這樣產(chǎn)生的代碼讀起來也很容易 get set

但是JavaBeans模式有一個缺點。因為構(gòu)造過程被分到了幾個調(diào)用中,在構(gòu)造過程中JavaBean可能處于不一致的狀態(tài),也就是說,JavaBean是非線程安全的。

JavaBeans模式阻止了把類做成不可變的可能。set


#構(gòu)建器 Builder

/**
 * Create By IntelliJ IDEA.
 *
 * @Author: Cheng
 * @Date: 2017/10/30
 * @Time: 18:34
 * <p>
 * 構(gòu)建器模式
 */

/**
 * 用戶類
 *
 * 帳號和密碼必須輸入
 * id不賦值表示未存入數(shù)據(jù)庫
 * 郵箱、手機、地址為選填項
 */
public class User {
    private String name;        // required
    private String password;    // required

    private int id;             // optional
    private String email;       // optional
    private String phone;       // optional
    private String address;     // optional

    /**
     * 構(gòu)造方法傳入構(gòu)造器
     * @param builder
     */
    private User(Builder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.password = builder.password;
        this.email = builder.email;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    /**
     * User類的構(gòu)造器
     * 選填屬性設(shè)置默認值
     *
     * 必須傳入的屬性由構(gòu)造器傳入設(shè)置
     * 選填屬性由方法設(shè)置
     */
    public static class Builder {
        private String name;
        private String password;

        private int id = -1;
        private String email = "未設(shè)置";
        private String phone = "未設(shè)置";
        private String address = "未設(shè)置";

        public Builder(String name, String password) {
            this.name = name;
            this.password = password;
        }

        /**
         * 返回的是建造器對象
         * @param email
         * @return
         */
        public Builder setEmail(String email) {
            this.email = email;
            return this;
        }

        public Builder setPhone(String phone) {
            this.phone = phone;
            return this;
        }

        public Builder setAddress(String address) {
            this.address = address;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }

    // 不提供 setter 方法,該對象就是不可變的了。也就是說,保證了同步性。
}

擁有重疊構(gòu)造器模式的安全性,也能保證JavaBean模式那么好的代碼可讀性。這就是 Builder 模式的一種形式。

不直接生成想要的對象,而是讓客戶端利用所有必要的參數(shù)調(diào)用構(gòu)造器,得到一個
builder 對象。然后客戶端在 builder 對象上調(diào)用類似 setter 的方法來設(shè)置可選參數(shù)。最后調(diào)用無參的 build 方法來生成不可變的對象。

這個 builder 是它構(gòu)建的類的靜態(tài)成員類。

注意 User 被設(shè)計成不可變的了,所有的默認參數(shù)值都單獨放在一個地方。builder 的 setter 方法返回 builder 本身,以便把調(diào)用鏈接起來。下面是客戶端代碼:

public static void main(String[] args) {
        User user = new User.Builder("cheng", "********")
                .setEmail("qq.com")
                .setPhone("110")
                .setAddress("HangZhou")
                .build();

        System.out.println(user);
}

builder 就像個構(gòu)造器一樣,可以對器參數(shù)強加約束條件。buld 方法可以檢驗這些約束條件。

public User build() {
        // 校驗邏輯
        return new User(this);
}

不足

  1. 比起另外兩種創(chuàng)建模式,Builder 模式多創(chuàng)建了一個構(gòu)建器對象。
  2. 代碼量比重疊構(gòu)造器模式更加冗長。

#總結(jié)

如果類的構(gòu)造器中具有多個參數(shù),并且對安全有要求,設(shè)置這種類時,Builder 模式就是種不錯的選擇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 文章作者:Tyan博客:noahsnail.com Item 2: Consider a builder when...
    SnailTyan閱讀 696評論 0 1
  • 上一篇文章設(shè)計模式-單例模式我們介紹了單例模式的幾種用法和優(yōu)缺點,具體的我們需要結(jié)合項目中的場景去具體選擇。這一篇...
    i卓閱讀 389評論 0 1
  • 1.什么是builder模式 簡單解釋,在程序設(shè)計的時候,如果面對的對象屬性較多,對象復雜性比較大(例如對象包...
    DevSiven閱讀 535評論 2 5
  • Builder模式 定義:將一個復雜對象的構(gòu)建和它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。 使用場景:(...
    ping_平閱讀 381評論 0 2
  • Builder模式可以稱為建造者模式,它將一個復雜對象的構(gòu)建和表示分離,同樣的構(gòu)建過程可以創(chuàng)建不同的表示 適用場景...
    KevinLive閱讀 745評論 0 0

友情鏈接更多精彩內(nèi)容