前言
其他創(chuàng)建型模式:
今天來(lái)介紹創(chuàng)建型模式之Builder(生成器)洗搂。Builder模式在Android開發(fā)中我們遇到很多燕垃,無(wú)論是平時(shí)的開發(fā),還是在閱讀Android源碼的過程都會(huì)遇到躲胳。例如Android源碼中:
- app核心層: Notification.Builder(android.app)
- 圖形繪制層:TypeFace.Builder(android.graphics)
- 底層硬件層:BluetoothDeviceFilter.Builder(android.companion)
- 網(wǎng)絡(luò)層:Uri.Builder(android.net)
可以發(fā)現(xiàn)糠排,在Android的源碼框架中灶轰,Builder模式的運(yùn)用真的是非常普遍冤荆。
大家可以通過快捷鍵在Android源碼當(dāng)中搜索Builder即可辽话。最常見的就是AlertDialog.Builder對(duì)象扔役,如下圖所示:
可以看到這么多方法才使得我們?cè)赾oding時(shí)去create一個(gè)Dialog對(duì)象的時(shí)候才能隨心所欲帆喇,Android中創(chuàng)建Dialog的這種方式,充分的體現(xiàn)了Builder模式的強(qiáng)大和靈活亿胸。
接下來(lái)我們來(lái)具體學(xué)習(xí)Builder模式:
1. 意圖
將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離坯钦,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
2. 適用性
- 當(dāng)創(chuàng)建復(fù)雜對(duì)象的算法應(yīng)該獨(dú)立于該對(duì)象的組成部分以及它們的裝配方式時(shí)侈玄。
- 當(dāng)構(gòu)造過程必須允許被構(gòu)造的對(duì)象有不同的表示時(shí)婉刀。
3. 參與者
- Builder —— 為創(chuàng)建一個(gè)Product對(duì)象的各個(gè)部件指定抽象接口。
-
ConcreteBuilder
—實(shí)現(xiàn)Builder的接口以構(gòu)造和裝配該產(chǎn)品的各個(gè)部件序仙。
— 定義并明確它所創(chuàng)建的表示突颊。
— 提供一個(gè)檢索產(chǎn)品的接口。 - Director —— 構(gòu)造一個(gè)使用Builder接口的對(duì)象潘悼。
-
Product
— 表示被構(gòu)造的復(fù)雜對(duì)象律秃。ConcreteBuilder創(chuàng)建該產(chǎn)品的內(nèi)部表示并定義它的裝配過程。
— 包含定義組成部件的類治唤,包含將這些部件裝配成最終產(chǎn)品的接口棒动。
4. 效果
1)它使你可以改變一個(gè)產(chǎn)品的內(nèi)部表示時(shí)
2)它將構(gòu)造代碼和表示代碼分開
3)它使你對(duì)構(gòu)造過程進(jìn)行更精細(xì)的控制
5. 實(shí)例
我們還是以汽車為例子,
汽車一般一共由五大部分組成:
- 發(fā)動(dòng)機(jī)(Engine)
- 傳動(dòng)系統(tǒng)(Power)
- 車身(body)
- 轉(zhuǎn)向(Steering)
- 懸掛(Suspension)
那么就可以抽象出對(duì)應(yīng)的Builder接口:
CarBuilder.java
public interface CarBuilder {
/**
* 構(gòu)建發(fā)動(dòng)機(jī)
*/
void buildEngine();
/**
* 構(gòu)建傳動(dòng)系統(tǒng)
*/
void buildPower();
/**
* 構(gòu)建車身
*/
void buildBody();
/**
* 構(gòu)建轉(zhuǎn)向
*/
void buildSteering();
/**
* 構(gòu)建懸掛
*/
void buildSuspension();
Car buildCar();
那么對(duì)應(yīng)的參與者Product就是汽車本身宾添,這里我們以寶馬和奧迪來(lái)進(jìn)行舉例:
對(duì)應(yīng)的ConcreteBuilder 就是AudiBuilder和BmwBuilder船惨,如下圖
然后需要一個(gè)Director的角色來(lái)指導(dǎo)不同的Car的構(gòu)建:
CarDirector.java
public class CarDirector {
public Car buildCar(CarBuilder carBuilder) {
carBuilder.buildBody();
carBuilder.buildEngine();
carBuilder.buildPower();
carBuilder.buildSteering();
carBuilder.buildSuspension();
return carBuilder.buildCar();
}
}
最后我們來(lái)測(cè)試一下:
private static void testBuilder() {
CarDirector carDirector = new CarDirector();
//構(gòu)建奧迪車
final Car audiCar = carDirector.buildCar(new AudiCarBuilder());
System.out.println(audiCar.toString());
//構(gòu)建寶馬車
final Car bmwCar = carDirector.buildCar(new BmwCarBuilder());
System.out.println(bmwCar.toString());
}
測(cè)試結(jié)果下圖所示:
實(shí)踐完汽車的這個(gè)簡(jiǎn)單的實(shí)例,我們?cè)賮?lái)看一下Android中經(jīng)典的Builder模式之AlertDialog.Builder:
//很經(jīng)典的鏈?zhǔn)秸{(diào)用有木有(一氣呵成)
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("title")
.setMessage("message")
.create();
dialog.show();
通過閱讀AlertDialog.Builder源碼缕陕,可以看出Builder類是屬于AlertDialog類的一個(gè)靜態(tài)內(nèi)部類粱锐,由源碼過多,我們只分析部分構(gòu)建過程:
public class AlertDialog extends Dialog implements DialogInterface {
//.....此處省略若干行代碼
public static class Builder {
private final AlertController.AlertParams P;
public Builder(Context context) {
this(context, resolveDialogTheme(context, ResourceId.ID_NULL));
}
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public AlertDialog create() {
//構(gòu)建一個(gè)新AlertDialog對(duì)象榄檬,并通過AlertController.AlertParams配置Dialog
final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
public AlertDialog show() {
final AlertDialog dialog = create();
dialog.show();
return dialog;
}
//.....此處省略若干行代碼
}
}
和構(gòu)造汽車的Builder模式相比較卜范,AlertDialog.Builder缺少了Director角色,但是這并不影響B(tài)uilder模式的效果鹿榜,其精髓之處就是體現(xiàn)在程序員一步步構(gòu)建Dialog對(duì)象的時(shí)候,其實(shí)也可以把具體使用Dialog情景或者方法體看成是一個(gè)虛的Director锦爵。
第三方庫(kù)中Builder的使用
另外Builder的構(gòu)建經(jīng)常在靜態(tài)工廠的構(gòu)建對(duì)象或者作為第三方庫(kù)使用的時(shí)候出現(xiàn)舱殿,比如知乎開源的一個(gè)強(qiáng)大圖片選擇器Matisse
在使用Matisse的時(shí)候就是經(jīng)典的鏈?zhǔn)秸{(diào)用+Builder模式,這里Matisse本身其實(shí)就是Builder !!!
Matisse.from(MainActivity.this)
.choose(MimeType.allOf())
.countable(true)
.maxSelectable(9)
.addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))
.gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
.thumbnailScale(0.85f)
.imageEngine(new GlideEngine())
.forResult(REQUEST_CODE_CHOOSE);
大家有興趣可以去閱讀以下它的源碼险掀,另外這里面還應(yīng)用了其他模式沪袭,例如代理模式、模板方法等樟氢,這里會(huì)在后續(xù)的文章進(jìn)行介紹冈绊。
6. 總結(jié)
Abstract Factory與Builder相似侠鳄,因?yàn)樗部梢詣?chuàng)建復(fù)雜對(duì)象。主要的區(qū)別就是Builder模式著重于一步步構(gòu)造一個(gè)復(fù)雜的對(duì)象死宣。而Abstract Factory著重于多個(gè)系列產(chǎn)品的對(duì)象的構(gòu)建伟恶。Builder在最后一步產(chǎn)品返回的時(shí)候,對(duì)于Abstract Factory來(lái)說毅该,產(chǎn)品是立即返回的博秫。