30分鐘學(xué)透設(shè)計模式2-隨處可見的Builder模式

聲明:原創(chuàng)文章兵钮,轉(zhuǎn)載請注明出處句占。http://www.reibang.com/p/afffb69232ac

設(shè)計模式系列:
30分鐘學(xué)透設(shè)計模式1-單例模式的前世今生
30分鐘學(xué)透設(shè)計模式2-隨處可見的Builder模式
30分鐘學(xué)透設(shè)計模式3-使用最多的Iterator模式
30分鐘學(xué)透設(shè)計模式4-最簡單的面向接口編程-簡單工廠模式
30分鐘學(xué)透設(shè)計模式5-從代理模式到AOP

一萌抵、概述

Builder模式:主要用于復(fù)雜對象的構(gòu)建棍丐,通過使用該模式可以有效地減少構(gòu)造函數(shù)或方法傳入的參數(shù)數(shù)量渠牲。
這對于有很多配置項的來初始化的對象非常適用。

通俗的講泌参,builder模式是一步步地創(chuàng)建一個超級復(fù)雜的對象脆淹。
它允許用戶僅通過復(fù)雜對象的類型和內(nèi)容就可以構(gòu)建,完全不需要知道其內(nèi)部細(xì)節(jié)沽一。

總之盖溺,builder模式,不僅可以讓構(gòu)造函數(shù)瘦身铣缠,對非構(gòu)造方法同樣適用烘嘱。

建造者

二、萬年不變的學(xué)生信息管理

上面的概念看起來還是一頭霧水蝗蛙,不知道這個builder模式到底有什么用蝇庭。
那我們通過一個學(xué)生信息管理的例子逐步來說明builder模式的使用方法。

1捡硅、起源

有這樣一個類遗契,記錄了學(xué)生信息。其中學(xué)號病曾、姓名牍蜂、性別和年齡為必須項,其他為非必須項泰涂。

public class Student {
    private int id; // 學(xué)號
    private String name; // 姓名
    private boolean sex; // 性別
    private int age; // 年齡
    // 非必須項
    private String addr; // 家庭地址
    private String phone; // 電話
    private String email; // 郵件
}

我們想要構(gòu)造這樣一個類的實例鲫竞,首先想到的是這樣去做。

public Student(int id, String name, boolean sex, int age,
                        String addr, String phone, String email) {
    this.id = id;
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.addr = addr;
    this.phone = phone;
    this.email = email;
}

假設(shè)有個學(xué)生小王逼蒙,上面7項信息都有从绘,可以這樣使用。
接下來是牢,學(xué)生小李僵井,只有4項基本信息,其他項都不知道驳棱,那我們怎么去做批什?
很簡單...

Student student = new Student(1, "Li", true, 18,"", "", "");

這樣讓我們很難區(qū)分出后面三項參數(shù)的具體含義。
當(dāng)然社搅,我們有更高級的方法去做驻债,例如重載構(gòu)造函數(shù):

public Student(int id, String name, boolean sex, int age) {
    this(id, name, sex, age, "");
}
public Student(int id, String name, boolean sex, int age, String addr) {
    this(id, name, sex, age, addr, "", "");
}

這里我們可以重載多個構(gòu)造函數(shù),第一個構(gòu)造4個參數(shù)形葬,第二個構(gòu)造5個參數(shù)合呐,以此類推,最終包含所有的參數(shù)笙以。
額淌实,這未免過于繁瑣,而且也不利于閱讀猖腕。

2拆祈、使用JavaBeans settter進行優(yōu)化

使用setter優(yōu)化話,大概是下面這個樣子谈息,這也是我們經(jīng)吃狄伲看到和使用的。

Student student = new Student();
student.setId(1);
student.setName("Li");
student.setSex(true);
student.setAge(18);
student.setAddr("BeiJing");
student.setPhone("13888888888");

同樣地侠仇,使用setter方法會產(chǎn)生大量重復(fù)的代碼轻姿,而且代碼外觀看起來不是很優(yōu)雅。
并且逻炊,JavaBeans模式有著嚴(yán)重的缺點互亮,構(gòu)造過程分散到多個setter方法中,構(gòu)造過程中由于多線程操作余素,JavaBean可能處于不一致狀態(tài)豹休。

3、使用優(yōu)雅地Builder模式

先看下結(jié)果:

Student student = new Student.Builder()
    .setId(1)
    .isFemale(false)
    .setName("Li")
    .setAge(18)
    .build();

這種形式的代碼是不是非常熟悉呢桨吊?

比如這樣:

String str = new StringBuilder()
    .append("ab")
    .reverse()
    .toString();

再比如這樣:

URI uri = new URIBuilder("http://www.baidu.com")
     .setPath("/hello")
     .setParameter("user", "Li")
     .setParameter("pwd", "123456")
     .build();

// custom() 實際上返回一個 HttpClientBuilder
HttpClient client = HttpClients.custom().build();

System.out.println(client.execute(new HttpGet(uri)));

是不是非常熟悉呢威根?尤其是上面發(fā)送Http請求這個例子凤巨,構(gòu)造Client和URI都是使用的Builder模式。

那這種代碼是怎么實現(xiàn)的呢洛搀?

4敢茁、動手實現(xiàn)一個Builder

Student類中增加靜態(tài)內(nèi)部類:

public static class Builder {
    private int id;
    private String name;
    private boolean sex;
    private int age;
    private String addr;
    private String phone;
    private String email;

    public Builder setId(int id) {
        this.id = id;
        return this;
    }
   public Builder setName(String name) {
        this.name = name;
        return this;
   }
    public Builder isFemale(boolean sex) {
        this.sex = sex;
        return this;
    }
    public Builder setAge(int age) {
        this.age = age;
        return this;
    }
   // ... 篇幅有限,省略其他的settter
    public Student build() {
        return new Student(this.id, this.name, this.sex, this.age, 
            this.addr, this.phone, this.email); 
    }
}

在客戶端調(diào)用時:

Student student = new Student.Builder()
     .setId(1)
    .isFemale(false)
    .setName("Li")
    .setAge(18)
    .build();

是不是非常簡單呢留美?那custom()那種的是什么情況彰檬?

假設(shè)我們有個Class類來管理學(xué)生,當(dāng)然學(xué)生這個場景不能很好的描述問題:

public class Class {
    public static Student.Builder custom() {
        return new Student.Builder();
    }
}

那我們實際調(diào)用的就會是:

Student student = Class.custom()
    .setId(1)
    .setName("Li")
    .isFemale(false)
    .setAge(18)
    .build();

上面的HttpClients中谎砾,實際有多個生成Client的方式逢倍,如默認(rèn)的,最小的等等景图。custom()只是生成一種通用的而已较雕。

三、優(yōu)缺點以及常見使用場景

1症歇、缺點

  • 使用builder模式郎笆,會額外的增加代碼(多寫一遍屬性和其setter方法),但對于客戶端來講忘晤,代碼可讀性會大大增強宛蚓。
  • 由于builder會多寫一遍setter方法,在屬性非常多的時候设塔,開發(fā)者可能會漏掉一兩個凄吏。

2、缺點

  • 使用builder模式闰蛔, 客戶端無需了解產(chǎn)品內(nèi)部組成的細(xì)節(jié)痕钢,將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對象序六。
  • 每一個具體建造者都相對獨立任连,而與其他的具體建造者無關(guān),程序更便于擴展例诀。

3随抠、場景

如果構(gòu)建對象時,屬性方法太多繁涂,可以試一試builder模式拱她。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扔罪,隨后出現(xiàn)的幾起案子秉沼,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唬复,死亡現(xiàn)場離奇詭異矗积,居然都是意外死亡,警方通過查閱死者的電腦和手機敞咧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門漠魏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妄均,你說我怎么就攤上這事∧淖裕” “怎么了丰包?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長壤巷。 經(jīng)常有香客問我邑彪,道長,這世上最難降的妖魔是什么胧华? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任寄症,我火速辦了婚禮,結(jié)果婚禮上矩动,老公的妹妹穿的比我還像新娘有巧。我一直安慰自己,他們只是感情好悲没,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布篮迎。 她就那樣靜靜地躺著,像睡著了一般示姿。 火紅的嫁衣襯著肌膚如雪甜橱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天栈戳,我揣著相機與錄音岂傲,去河邊找鬼。 笑死子檀,一個胖子當(dāng)著我的面吹牛镊掖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播命锄,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼堰乔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了脐恩?” 一聲冷哼從身側(cè)響起镐侯,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后苟翻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體韵卤,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年崇猫,在試婚紗的時候發(fā)現(xiàn)自己被綠了沈条。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡诅炉,死狀恐怖蜡歹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涕烧,我是刑警寧澤月而,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站议纯,受9級特大地震影響父款,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞻凤,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一憨攒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧阀参,春花似錦肝集、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至炕吸,卻和暖如春伐憾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赫模。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工树肃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瀑罗。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓胸嘴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親斩祭。 傳聞我的和親對象是個殘疾皇子劣像,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345