導(dǎo)語(yǔ)
Builder模式是一步一步創(chuàng)建一個(gè)復(fù)雜對(duì)象的創(chuàng)建型模式(有的地方叫建造者模式),它允許用戶(hù)在不知道內(nèi)部構(gòu)建細(xì)節(jié)的情況下,可以更精細(xì)地控制對(duì)象的構(gòu)造流程狡耻。該模式是為了將構(gòu)建復(fù)雜對(duì)象的過(guò)程和它的部件解耦,使得構(gòu)建過(guò)程和部件的表示隔離開(kāi)來(lái)。
主要內(nèi)容
- Builder模式的定義
- Builder模式的使用場(chǎng)景
- Builder模式的UML類(lèi)圖
- Builder模式的實(shí)現(xiàn)方式
具體內(nèi)容
Builder模式的定義
將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離界轩,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。
Builder模式的使用場(chǎng)景
- 相同的方法衔瓮,不同的執(zhí)行順序浊猾,產(chǎn)生不同的事件結(jié)果時(shí)。
- 多個(gè)部件或零件热鞍,都可以裝配到一個(gè)對(duì)象中葫慎,但是產(chǎn)生的運(yùn)行結(jié)果又不相同時(shí)。
- 產(chǎn)品類(lèi)非常復(fù)雜薇宠,或者產(chǎn)品類(lèi)中的調(diào)用順序不同產(chǎn)生了不同的效能偷办,這個(gè)時(shí)候使用建造者模式非常合適。
- 當(dāng)初始化一個(gè)對(duì)象特別復(fù)雜澄港,如參數(shù)多椒涯,且很多參數(shù)都具有默認(rèn)值時(shí)。
Builder模式的UML類(lèi)圖
Builder模式的UML類(lèi)圖如下所示回梧。
角色介紹:
- Product 產(chǎn)品類(lèi) : 產(chǎn)品的抽象類(lèi)废岂。
- Builder : 抽象類(lèi)祖搓, 規(guī)范產(chǎn)品的組建,一般是由子類(lèi)實(shí)現(xiàn)具體的組件過(guò)程泪喊。
- ConcreteBuilder : 具體的構(gòu)建器.
- Director : 統(tǒng)一組裝過(guò)程(可省略)棕硫。
Builder模式的實(shí)現(xiàn)方式
電腦的組裝過(guò)程較為復(fù)雜,步驟繁多袒啼,但是順序卻是不固定的哈扮。下面我們以組裝電腦為例來(lái)演示一下簡(jiǎn)單且經(jīng)典的builder模式。
計(jì)算機(jī)抽象類(lèi)蚓再,即Products角色:
package com.dp.example.builder;
/**
* Computer產(chǎn)品抽象類(lèi), 為了例子簡(jiǎn)單, 只列出這幾個(gè)屬性
*/
public abstract class Computer {
protected String mBoard;
protected String mDisplay;
protected String mOs;
protected Computer() {
}
// 設(shè)置主板
public abstract void setBoard(String board){
this.mBoard = board;
}
// 設(shè)置顯示器
public void setDisplay(String display){
this.mDisplay = display;
}
// 設(shè)置操作系統(tǒng)
public void setOs();
@Override
public String toString() {
return "Computer [mBoard = " + mBoard + ", mDisplay = " + mDisplay + ", mOs = " + mOs + "]";
}
}
具體的Computer類(lèi)滑肉,Macbook
package com.dp.example.builder;
/**
* Mac電腦
*/
public class Macbook extends Computer {
protected Macbook() {
}
@Override
public void setOs() {
mOs = "Mac OS X 10.10";
}
}
抽象Builder類(lèi):
package com.dp.example.builder;
/**
* builder抽象類(lèi)
*/
public abstract class Builder {
// 設(shè)置主板
public abstract void buildBoard(String board);
// 設(shè)置顯示器
public abstract void buildDisplay(String display);
// 設(shè)置操作系統(tǒng)
public abstract void buildOs();
// 創(chuàng)建Computer
public abstract Computer create();
}
具體的Builder類(lèi),MacbookBuilder:
package com.dp.example.builder;
public class MacbookBuilder extends Builder {
private Computer mComputer = new Macbook();
@Override
public void buildBoard(String board) {
mComputer.setBoard(board);
}
@Override
public void buildDisplay(String display) {
mComputer.setDisplay(display);
}
@Override
public void buildOs() {
mComputer.setOs();
}
@Override
public Computer create() {
return mComputer;
}
}
Director類(lèi)摘仅,負(fù)責(zé)構(gòu)造Computer:
package com.dp.example.builder;
public class Director {
Builder mBuilder = null;
/**
* @param builder
*/
public Director(Builder builder) {
mBuilder = builder;
}
/**
* 構(gòu)建對(duì)象
*
* @param board
* @param display
* @param os
*/
public void construct(String board, String display) {
mBuilder.buildCPU(board);
mBuilder.buildRAM(display);
mBuilder.buildOs();
}
}
測(cè)試代碼:
/**
* 經(jīng)典實(shí)現(xiàn)較為繁瑣
*
* @author mrsimple
*
*/
public class Test {
public static void main(String[] args) {
// 構(gòu)建器
Builder builder = new MacbookBuilder();
// Director
Director pcDirector = new Director(builder);
// 封裝構(gòu)建過(guò)程
pcDirector.construct("英特爾主板", "Retina顯示器");
// 構(gòu)建電腦靶庙,輸出相關(guān)信息
System.out.println("Computer Info : " + builder.create().toString());
}
}
輸出結(jié)果:
Computer Info : Computer [mBoard = 英特爾主板, mDisplay = Retina顯示器, mOs = Mac OS X 10.10]
上述示例中,通過(guò)具體的MacbookBuilder來(lái)構(gòu)建Macbook對(duì)象娃属,而Directory封裝了構(gòu)建復(fù)雜產(chǎn)品對(duì)象的過(guò)程六荒,對(duì)處隱藏構(gòu)建細(xì)節(jié)。Builder與Director一起將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離矾端,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的對(duì)象掏击。
值得注意的是,在現(xiàn)實(shí)開(kāi)發(fā)過(guò)程中秩铆,Directory角色經(jīng)常會(huì)被省略砚亭。而直接使用一個(gè)Builder來(lái)進(jìn)行對(duì)象的組裝,這個(gè)Builder通常為鏈?zhǔn)秸{(diào)用殴玛,它的關(guān)鍵點(diǎn)是每個(gè)setter方法都返回自身捅膘,也就是return this,這樣就使得setter方法可以鏈?zhǔn)秸{(diào)用滚粟,代碼大致如下:
new TestBuilder().setA("A").setB("B").create();
通過(guò)這種形式不僅去除了Director角色寻仗,整個(gè)結(jié)構(gòu)也更加簡(jiǎn)單,也能對(duì)Product對(duì)象的組裝過(guò)程有更精細(xì)的控制坦刀。
總結(jié)
Builder模式在Android開(kāi)發(fā)中也較為常用愧沟,通常作為配置類(lèi)的構(gòu)建器將配置的構(gòu)建和表示分離開(kāi)來(lái),同時(shí)也是將配置從目標(biāo)類(lèi)中隔離出來(lái)鲤遥,避免過(guò)多的setter方法沐寺。Builder模式比較常見(jiàn)的實(shí)現(xiàn)形式是通過(guò)調(diào)用鏈實(shí)現(xiàn),這樣使得代碼更簡(jiǎn)潔盖奈、易懂混坞。
-
優(yōu)點(diǎn):
- 良好的封裝性, 使用建造者模式可以使客戶(hù)端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)。
- 建造者獨(dú)立究孕,容易擴(kuò)展啥酱。
- 在對(duì)象創(chuàng)建過(guò)程中會(huì)使用到系統(tǒng)中的一些其它對(duì)象,這些對(duì)象在產(chǎn)品對(duì)象的創(chuàng)建過(guò)程中不易得到厨诸。
-
缺點(diǎn):
- 會(huì)產(chǎn)生多余的Builder對(duì)象以及Director對(duì)象镶殷,消耗內(nèi)存。