我們構(gòu)造一個(gè)類常用的有兩種方式
一種方式是采用多重載的構(gòu)造函數(shù),把不同搭配的屬性寫成不同的構(gòu)造函數(shù)爽待,這種方式的缺點(diǎn)在于代碼的重復(fù)工作量會非常大,而且用戶在用的時(shí)候很難分清楚每一種構(gòu)造函數(shù)是干什么的翩腐,而且參數(shù)順序輸不對可是個(gè)大問題鸟款,使用起來十分不方便。
另一種方法是通過get茂卦,set的方法何什,這種方法比較容易理解,但是缺點(diǎn)也很明顯等龙,一個(gè)是參數(shù)變量不能是final類型处渣,而且用戶不知道什么時(shí)候他才能得到一個(gè)完整的變量(比方說用戶還有很重要的屬性沒有set就去使用這個(gè)變量了)
針對以上的缺點(diǎn),我們采用builder模式去構(gòu)建一個(gè)新的對象
傳統(tǒng)builder模式
傳統(tǒng)建造者模式包含四個(gè)角色
- builder(抽象構(gòu)造者):這個(gè)是一個(gè)抽象類或者接口罐栈,用于抽象具體建造者的函數(shù)。
- ConcreteBuilder(具體建造者):這是抽象構(gòu)造者的具體實(shí)現(xiàn)泥畅,實(shí)現(xiàn)構(gòu)造邏輯
- Director (指導(dǎo)者):可以叫指導(dǎo)者荠诬,也可以叫服務(wù)員,他不需要知道builder是如何建造產(chǎn)品的,用戶直接和指導(dǎo)者進(jìn)行溝通柑贞,指導(dǎo)者有兩種操作:告訴builder去建造一個(gè)商品方椎;把商品交付給用戶
- Product (產(chǎn)品類):這是我們具體要構(gòu)造的的對象。
代碼
產(chǎn)品類
public class Car
{
private String wheel;
private String skeleton;
private String engine;
// 省略getter和setter方法
}
抽象建造者類
public interface ICarBuilder
{
public void buildWheel();
public void buildSkeleton();
public void buildEngine();
Car buildCar();
}
具體建造者類
public class ConcreteBuilder implements ICarBuilder
{
Car car;
public ConcreteBuilder()
{
car = new Car();
}
@Override
public ConcreteBuilder buildWheel()
{
car.setWheel("輪子");
}
@Override
public ConcreteBuilder buildSkeleton()
{
car.setSkeleton("車身結(jié)構(gòu)");
}
@Override
public ConcreteBuilder buildEngine()
{
car.setEngine("發(fā)動機(jī)");
}
//前面那些builder方法返回的都是builder钧嘶,只有當(dāng)調(diào)用下面的build方法的時(shí)候才最終構(gòu)建出了該對象
@Override
public Car buildCar()
{
return this.car;
}
}
public class CarDirector
{
public Car constructCar(ICarBuilder builder)
{
builder.buildEngine();
builder.buildSkeleton();
builder.buildWheel();
return builder.buildCar();
}
}
public class MainTest
{
public static void main(String[] args)
{
CarDirector director = new CarDirector();//在使用的時(shí)候先聲明中間的服務(wù)員棠众,也就是指導(dǎo)者
Car car = director.constructCar(new ConcreteBuilder());//通過指導(dǎo)者把車構(gòu)建出來
System.out.println(car.getWheel());
System.out.println(car.getEngine());
System.out.println(car.getSkeleton());
}
}
此段代碼作者朱小廝 原文:https://blog.csdn.net/u013256816/article/details/50978024?utm_source=copy
主要優(yōu)點(diǎn)是
- 在建造過程中對象是未生成的,最后調(diào)用build方法之后才會生成該對象
- 有一個(gè)builder的interface有决,擴(kuò)展性更強(qiáng)闸拿,并且可以把build過程與交付給用戶的過程解耦開,使用更靈活疮薇,封裝性好
- 而且這也形成了漂亮的鏈?zhǔn)秸{(diào)用
Person person = new Person.PersonBuilder("cj")
.age(24)
.job("java")
.location("蘇州")
.builder();
變種builder模式
在上面的builder模式中胸墙,優(yōu)點(diǎn)顯而易見,可擴(kuò)展性強(qiáng)按咒,但是造成的結(jié)果是代碼冗余量大迟隅,憑空多了三個(gè)類,而且并不是所有的情況都需要多個(gè)不同實(shí)現(xiàn)的builder的励七,變種builder模式的主要目的是減少多余類的創(chuàng)建智袭,省略了builder抽象類和指導(dǎo)者。
代碼
這里主要結(jié)合OKHttp源碼講解
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final RequestBody body;
final Object tag;
private volatile CacheControl cacheControl; // Lazily initialized.
Request(Builder builder) {
//構(gòu)造函數(shù)掠抬,省略屬性賦值操作
}
public Builder newBuilder() {//這里讀者可以思考一下為什么會有一個(gè)newbuilder模式呢
return new Builder(this);
}
//省略部分代碼
public static class Builder {
HttpUrl url;
String method;
Headers.Builder headers;
RequestBody body;
Object tag;
//省略部分代碼
Builder(Request request) {//這里讀者可以想一想為什么在builder中會有這樣一個(gè)構(gòu)造方法吼野,既然我們在創(chuàng)造builder的時(shí)候request是空的,那我們什么時(shí)候會用到這個(gè)方法呢两波?
//構(gòu)造函數(shù)瞳步,省略屬性賦值操作
}
//省略部分代碼
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
}
在變種builder模式中,直接將指揮者和抽象builder類去掉了腰奋,取而代之的是靜態(tài)內(nèi)部類builder单起,犧牲了一部分的可擴(kuò)展性,將代碼邏輯大大簡化劣坊。
這種builder的作用和傳統(tǒng)builder是一樣的
這個(gè)時(shí)候有一個(gè)問題嘀倒,當(dāng)我的對象屬性相當(dāng)多,而且我現(xiàn)在要新建一個(gè)對象局冰,這個(gè)對象的屬性值只有一兩個(gè)和我已有的對象不同测蘑,這個(gè)時(shí)候我要怎么做?
粘貼上一段代碼康二?重新輸入?
畢竟builder模式創(chuàng)建的對象一但創(chuàng)建成功里面的屬性就不能再修改碳胳,所以拷貝一個(gè)對象再更改屬性的方法是不可行的
我在一開始讀OKhttp的源碼的時(shí)候也很好奇它里面為什么會有一個(gè)newBuilder方法,builder中會有一個(gè)參數(shù)為request的構(gòu)造方法赠摇,這里不得不驚嘆設(shè)計(jì)者的強(qiáng)大固逗,原文在此
public Builder newBuilder() {
return new Builder(this);
}
這里通過原有的request的newBuilder方法生成一個(gè)新的浅蚪,并且屬性值和request一樣的builder,之后再用這個(gè)新的builder更改屬性后生成新的request烫罩。
巧妙地通過產(chǎn)品構(gòu)造出builder惜傲,更改builder產(chǎn)生全新的產(chǎn)品。通過逆向構(gòu)造的過程完成了整個(gè)拷貝
對比傳統(tǒng)builder模式和變種builder模式
傳統(tǒng)的builder模式優(yōu)點(diǎn)是可擴(kuò)展性強(qiáng)贝攒,但是同時(shí)缺點(diǎn)是要?jiǎng)?chuàng)造4個(gè)類盗誊,對于初學(xué)者很不友好,而且代碼冗余量大隘弊,變種builder使用更加便捷哈踱,操作更加方便