聲明:原創(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模式拱她。