建造者(Builder)模式

前言

建造者模式即BUilder模式,看名字就可知是一種創建型模式。主要是解決

  1. 構造方法中參數過多導致的可讀性較差的問題;
  2. 在初始化時不必將所有參數進行設置的情況(通常有默認值)。
    文中會舉例進行演示,通過例子能夠有一個更清晰的認識。

場景描述

許多游戲在進入游戲時,第一步往往是讓我們選擇角色的外形,如眼睛顏色,眼睛大小,發型,頭發顏色,臉型等等。假設現在要創建一個小明,大眼,綠色的瞳孔,中分頭,紅色頭發,鞋拔子臉。當然還有必填的姓名。

首先,我們創建一個Person的類,并改寫toString方法便于測試。

public class Person {
    private String name;//姓名必填
    private String eyeSize;//眼睛大小
    private String eyeColor;//眼睛顏色
    private String hairStyle;//發型
    private String hairColor;//頭發顏色
    private String face;//臉型

    public Person(String name, String eyeSize, String eyeColor, String hairStyle, String hairColor, String face) {
        this.name = name;
        this.eyeSize = eyeSize;
        this.eyeColor = eyeColor;
        this.hairStyle = hairStyle;
        this.hairColor = hairColor;
        this.face = face;
    }

    @Override
    public String toString() {
        String s = "姓名:" + name + "\n"
                + "眼睛:" + eyeSize + "\n"
                + "眼睛顏色:" + eyeColor + "\n"
                + "發型:" + hairStyle + "\n"
                + "頭發顏色:" + hairColor + "\n"
                + "臉型:" + face;
        return s;
    }
}

同時我們編寫測試類,創建小明這個角色。在創建時我郁悶了,在通過構造方法對對象進行初始化時,我忘記了參數的順序。雖然現在IDE都非常的智能,會對參數進行提示,但是還是影響了我的開發效率。

最后我們艱辛的創建完了這個簡單的測試類

public static void main(String[] args) {

    Person xiaoming = new Person("小明","大", "綠色", "中分", "紅色", "鞋拔子臉");

    System.out.println(xiaoming.toString());

}

輸入結果如下:

姓名:小明
眼睛:大
眼睛顏色:綠色
發型:中分
頭發顏色:紅色
臉型:鞋拔子臉

老鐵,沒毛病。但是現在是只有6個參數的情況下,似乎還可以接受,但是如果再多幾個,orz!!

使用Builder模式

首先來說說使用Builder模式有什么優點:

  1. 默認參數,無需對所有參數進行初始化;
  2. 將實現變成鏈式調用,增加了代碼可讀性。

現在不管角色的外形,我只想創建一個小明的對象,來看看Builder模式會怎么做:

public static void main(String[] args) {
    Person xiaoming = new Person.Builder("小明").create();

    System.out.println(xiaoming.toString());
}
圖片.png

Are you kidding?就傳了個必填項姓名就創建好了?僅用一行代碼就創建好了這個對象。

在前言中講到過一點,設置默認值。以上實現就是基于默認值的設置。

接下來就來到了緊張刺激的代碼實現環節。Builder的實現

public class Person {
    private String name;//姓名必填
    //省略其他可選參數

    private Person(Builder builder) {  //1............
        initialize(builder);
    }

    private void initialize(final Builder builder) {
        name = builder.name;
        //省略
    }


    public static class Builder {
        //2..........
        private String name;//姓名必填
        private String eyeSize = "大";//眼睛大小
        //省略

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

        public Builder setEyeSize(String eyeSize) {
            this.eyeSize = eyeSize;
            //3..........
            return this;
        }

        //省略

        //4..........
        public Person create() {
            return new Person(this);
        }
    }

    @Override
    public String toString() {
        String s = "姓名:" + name + "\n"
                + "眼睛:" + eyeSize + "\n"
                + "眼睛顏色:" + eyeColor + "\n"
                + "發型:" + hairStyle + "\n"
                + "頭發顏色:" + hairColor + "\n"
                + "臉型:" + face;
        return s;
    }
}

劃一下重點:

  1. 因為我們要用過Builder來創建對象,所有需將Person類的構造方法私有化,且通過Builder來構建;
  2. 在Builder中初始化變量,對外部提供set方法;
  3. 實現鏈式的關鍵 return this;
  4. 設置完參數之后通過Person類的構造進行構建并返回實例對象。

繼續創建一個好看點的小紅:

    Person xiaohong = new Person.Builder("小紅")
            .setEyeColor("藍色")
            .setEyeSize("大")
            .setFace("鵝蛋臉")
            .setHairStyle("大波浪")
            .setHairColor("褐色")
            .create();

是不是格外的清晰。

總結

將代碼寫成鏈式是非常優美的事情,像在Android開發中,我們可以將TitleBar的設置寫成鏈式,也可以將RecyclerView的初始化過程寫成鏈式;
看過dagger2生成的代碼就可以看出,文中builder模式是仿造它的實現,要是沒看過現在也可以轉去看,相信會輕松許多;
完整代碼移步gayhub

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容