模式介紹
Builder模式是指一步一步來構(gòu)建出一個復(fù)雜的對象。
它允許用戶在不知道內(nèi)部構(gòu)建細(xì)節(jié)的情況下,非常精細(xì)地控制對象構(gòu)建流程。
該模式是為了將構(gòu)建過程非常復(fù)雜的對象進(jìn)行拆分,讓它與它的部件解耦,提升代碼的可讀性以及擴(kuò)展性。
模式結(jié)構(gòu)
建造者模式包含如下角色:
- Product:產(chǎn)品角色
- Builder:抽象的建造者
- ConcreteBuilder:具體的建造者
- Director:指揮者
模式實(shí)例
我們來舉個生活中的例子來描述建造者模式的各個角色:
假設(shè)我們現(xiàn)在是一個手機(jī)的生產(chǎn)商,各大手機(jī)廠商都會來找我們制造手機(jī),比如小米、華為、三星、魅族等。每個廠商的手機(jī)配置都不一致,包括CPU型號、內(nèi)存大小、像素大小等等。
現(xiàn)在我們將這個例子中的對象轉(zhuǎn)化成建造者模式的各個角色:
- Product:我們生產(chǎn)的手機(jī)就是商品,Product中應(yīng)該包含手機(jī)的各個部件。
- Builder:抽象Builder類,細(xì)節(jié)全在ConcreteBuilder中。
- ConcreteBuilder:繼承了Builder類,這里有手機(jī)的組裝細(xì)節(jié)。
- Director:這里的指揮者就是各大手機(jī)廠商,我要讓你生產(chǎn)一臺小米手機(jī)并給了你一系列參數(shù),你就要按照參數(shù),生產(chǎn)我想要的手機(jī),其他手機(jī)也是同樣的同理。
紙上談兵終覺淺,我們將上述實(shí)例轉(zhuǎn)化成代碼看一看:
首先是Product,它應(yīng)該包含手機(jī)的構(gòu)成元素:
public class PhoneProduct {
private String brand;//品牌
private String CPU;//CPU
private String memorySize;//內(nèi)存大小
private String pixel;//像素大小
public void setBrand(String brand) {
this.brand = brand;
}
public void setCPU(String CPU) {
this.CPU = CPU;
}
public void setMemorySize(String memorySize) {
this.memorySize = memorySize;
}
public void setPixel(String pixel) {
this.pixel = pixel;
}
@Override
public String toString() {
return "品牌:" + brand +
"\nCPU:" + CPU +
"\n內(nèi)存大小:" + memorySize +
"\n像素大小:" + pixel;
}
我們可以看出,一臺手機(jī)的構(gòu)建元素有:品牌、CPU、內(nèi)存大小以及像素大小,如果還有其他元素,只需要繼續(xù)添加成員變量即可。
有了手機(jī)的構(gòu)建元素,如何將這些元素拼接成手機(jī),就是Builder要做的事情了:
public abstract class PhoneBuilder {
//構(gòu)建手機(jī)品牌
public abstract void buildBrand(String brand);
//構(gòu)建手機(jī)CPU
public abstract void buildCPU(String cpu);
//構(gòu)建手機(jī)內(nèi)存
public abstract void buildMemorySize(String memorySize);
//構(gòu)建手機(jī)像素大小
public abstract void buildPixel(String pixel);
//將各個零件進(jìn)行拼接
public abstract PhoneProduct create();
}
可以看到抽象的Builder類中有各個元素的組裝方法,并且最后還有一個組裝手機(jī)的方法:create()
。
接下來我們使用ConcreteBuilder來繼承Builder并實(shí)現(xiàn)具體的組裝細(xì)節(jié):
public class ConcretePhoneBuilder extends PhoneBuilder {
//商品手機(jī)
private PhoneProduct product = new PhoneProduct();
@Override
public void buildBrand(String brand) {
product.setBrand(brand);
}
@Override
public void buildCPU(String cpu) {
product.setCPU(cpu);
}
@Override
public void buildMemorySize(String memorySize) {
product.setMemorySize(memorySize);
}
@Override
public void buildPixel(String pixel) {
product.setPixel(pixel);
}
@Override
public PhoneProduct create() {
return product;
}
}
ConcreteBuilder中包含了每個零件組裝和最后拼接過程create()的所有細(xì)節(jié)。
到這里,我們作為一個手機(jī)生產(chǎn)商,已經(jīng)具備了生產(chǎn)手機(jī)的能力,接下來就要接待客戶了!
平時(shí)大家都說,客戶是上帝。今天在這里,也是如此。
所以起到主導(dǎo)作用的,就是我們的客戶Director:
public class PhoneDirector {
private PhoneBuilder builder;
public PhoneDirector(PhoneBuilder builder) {
this.builder = builder;
}
public PhoneProduct constuct(String brand, String cpu, String memorySize, String pixel) {
builder.buildBrand(brand);
builder.buildCPU(cpu);
builder.buildMemorySize(memorySize);
builder.buildPixel(pixel);
return builder.create();
}
}
可以看到Director中持有PhoneBuilder對象,這里的constuct(,,,,)就相當(dāng)于客戶的需求,告訴我們手機(jī)的具體配置,接著我們拿著具體需求去ConcreteBuilder中構(gòu)建具體的手機(jī),并返回給用戶。
整個建造者模式就是這樣的,接下來我們來做下簡單的測試:
//創(chuàng)建Builder對象
PhoneBuilder miBuilder = new ConcretePhoneBuilder();
//創(chuàng)建管理者
PhoneDirector director = new PhoneDirector(miBuilder);
//生成商品
PhoneProduct product = director.constuct("小米", "驍龍825", "4GB", "1500萬像素");
//展示構(gòu)建結(jié)果
textView.setText(product.toString());
首先創(chuàng)建Builder并傳遞給Director,接下來調(diào)用Director的構(gòu)建方法并傳遞需求,一臺手機(jī)就構(gòu)建出來了。
在這個過程中,管理者Director完全不知手機(jī)道構(gòu)建細(xì)節(jié)。代碼的擴(kuò)展性以及可讀性都有質(zhì)的提升。
模式變形
在剛剛接觸到Builder模式時(shí),我就發(fā)現(xiàn)了于我而言,一個非常巨大的應(yīng)用場景,完美解決一個讓我極其難受的問題。
由于篇幅問題,模式變形我決定新起一篇文章中解釋。
總結(jié)
Demo我已經(jīng)上傳至GitHub,各位看官可自行食用。
上面的例子,僅僅是個例子,看起來似乎僅僅是增加了工作量。
但事實(shí)并不是這樣的,這種寫法的擴(kuò)展性、可讀性都是有很大提升的,希望各位看官都可以理解這種代碼思想。
還有一點(diǎn)是,建造者模式與之后要講到的工廠模式類似,他們都是建造者模式,適用的場景也很相似。
一般來說,如果產(chǎn)品的建造很復(fù)雜,那么請用工廠模式;如果產(chǎn)品的建造更復(fù)雜,那么請用建造者模式。
感謝
《Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》 何紅輝、關(guān)愛民 著