Java 解決構造方法參數過多-builder模式(effect java 學習筆記2)

1、前景:

  通常狀況咱們不會遇到這樣的狀況,使用靜態工廠方法,或者構造方法就足夠。可是它們也有一個限制就是,它們不能很好的擴展到不少可選參數的場景。隨着咱們業務的深刻,某些java bean 中的參數將會愈來愈多,咱們添加的構造方法也相應的增長。想一想一個10個參數的構造方法,我胃痛。java

  既然想要用builder模式,咱們首先須要知道傳統方法的不足。程序員


2、可伸縮構造方法 VS builder模式

  咱們都用代碼實例來講話安全

一、可伸縮構造方法

public class Student {
    private final String name; // required
    private final String sex;  // required
    private final int weight;  // optional
    private final int height;  // optional 
    private final int age;     // optional

    public Student(String name, String sex) {
        this(name, sex, 0);
    }
    
    public Student(String name, String sex, int w) {
        this(name, sex, w, 0);
    }
    
    public Student(String name, String sex, int w, int h) {
        this(name, sex, w, h, 0);
    }

    public Student(String name, String sex, int w, int h, int a) {
        this.name = name;
        this.sex = sex;
        this.weight = w;
        this.height = h;
        this.age = a;
    }
}
複製代碼

當咱們想建立一個Student實例的時候,能夠設置全部參數的最短的夠着方法以下:bash

Student student = new Student("小明", "男", 50, 150, 16);微信

  一般狀況下,這個構造方法可能須要許多你不想設置的參數(是否是有點不爽),隨着參數的不斷增長,它很快會失控的。(你也會發瘋的)。首先咱們很難讀懂這個方法,其次若是反轉了兩個參數,編譯器是不會報錯的。好比身高和體重填反了,糟心。。。。。性能

二、JavaBean模式

  當在構造方法中遇到許多可選參數時,另外一種選擇是 JavaBeans 模式,在這種模式中,調用一個無參數的構造函 數來建立對象,而後調用 setter 方法來設置每一個必需的參數和可選參數:ui

public class Student {
    private  String name; // required
    private  String sex;  // required
    private  int weight;  // optional
    private  int height;  // optional
    private  int age;     // optional

    public Student() {}


    public void setName(String name) {
        this.name = name;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
複製代碼

這種模式沒有伸縮構造方法的缺點。有點冗長,但建立實例容易,而且容易閱讀this

Student student = new Student();
        student.setName("小明");
        student.setSex("男");
        student.setAge(16);
        student.setWeight(50);
        student.setHeight(150);
複製代碼

  JavaBeans 模式自己有嚴重的缺陷。因爲構造方法在屢次調用中被分割,因此在構造過程當中 JavaBean 可能處於不一致的狀態。該類沒有經過檢查構造參數參數的有效性來執行一致性的選項。在不一致的狀態下嘗試使用 對象可能會致使與包含 bug 的代碼截然不同的錯誤,所以很難調試。一個相關的缺點是,JavaBeans 模式排除了讓類 不可變的可能性,而且須要在程序員的部分增長工做以確保線程安全spa

三、builder模式

  builder 模式結合了可伸縮構造方法模式的安全性和JavaBean模式的可讀性。線程

public class Student {
    private final String name;
    private final String sex;
    private  final int weight;
    private final int height;
    private  final int age;

    private Student(Builder builder) {
        this.name = builder.name;
        this.sex = builder.sex;
        this.weight = builder.weight;
        this.height = builder.height;
        this.age = builder.age;
    }
    
    public static class Builder {
        private final String name; // required
        private final String sex;  // required
        private int weight;  // optional
        private int height;  // optional
        private int age;     // optional

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

        public Builder setWeight(int weight) {
            this.weight = weight;
            return this;
        }

        public Builder setHeight(int height) {
            this.height = height;
            return this;
        }
        
        public Builder setAge(int age) {
            this.age = age;
            return this;
        }
        
        public Student build() {
            return new Student(this);
        }

    }
}
複製代碼

  我首先來噴一下,代碼量翻倍了。可是Student 類是不可變的,全部的參數默認值都在一個地方。builder 的 setter 方法返回 builder 自己, 這樣調用就能夠被連接起來,從而生成一個流暢的 API。實例以下:

Student student = new Student.Builder("小明", "男").setWeight(50)
                .setHeight(150).setAge(16).build();
複製代碼

  代碼很容易編寫,更重要的是易於閱讀。 Builder 模式模擬 Python 和 Scala 中的命名可選參數。 這裏沒有涉及到有效性的檢查


總結:

  builder 對構造方法的一個微小的優點是,builder 能夠有多個可變參數,由於每一個參數都是在它本身的方法中指 定的。

  Builder 模式很是靈活。 單個 builder 能夠重複使用來構建多個對象。 builder 的參數能夠在構建方法的調用之間 進行調整,以改變建立的對象。 builder 能夠在建立對象時自動填充一些屬性,例如每次建立對象時增長的序列號。

  Builder 模式也有缺點。爲了建立對象,首先必須建立它的 builder。雖然建立這個 builder 的成本在實踐中不太可 能被注意到,但在性能關鍵的狀況下可能會出現問題。並且,builder 模式比伸縮構造方法模式更冗長,所以只有在 有足夠的參數時才值得使用它,好比四個或更多。可是請記住,若是但願在未來添加更多的參數。可是,若是從構造 方法或靜態工廠開始,並切換到 builder,當類演化到參數數量失控的時候,過期的構造方法或靜態工廠就會面臨尷 尬的處境。所以,因此,最好從一開始就建立一個 builder。

  總而言之,當設計類的構造方法或靜態工廠的參數超過幾個時,Builder 模式是一個不錯的選擇,特別是若是許 多參數是可選的或相同類型的。客戶端代碼比使用伸縮構造方法(telescoping constructors)更容易讀寫,而且 builder 比 JavaBeans 更安全。

ps:若是有微信讀書的書友,能夠來微信讀書羣傳送門找組織。

相關文章
相關標籤/搜索