1 介紹
建造者模式(Builder)瞭恰,又叫生成器模式巨税。是對象的創(chuàng)建模式适篙。建造者模式可以將產(chǎn)品的內(nèi)部表象與產(chǎn)品的生成過程分割開來昵观。從而可以使一個建造過程生成具有不同的內(nèi)部表象的產(chǎn)品對象碳抄。
1.1 什么是建造者模式
將一個復雜對象的構建與它的表示分離愉老,使得同樣的構建過程可以創(chuàng)建不同的表示。
1.2 解決什么樣的問題
如果我們用了建造者模式剖效,那么用戶就只需指定需要建造的類型就可以得到它們嫉入,而具體的建造過程和細節(jié)就不需要知道了。
由于建造角色的過程比較復雜璧尸,其中還有相互依賴關系咒林,所以我們使用建造者模式將將建造復雜對象的過程和組成對象的部件解耦。這樣既保證了基本屬性全都一致(這里的一致指的是該包含的應該全都包含)也封裝了其中的具體實現(xiàn)細節(jié)爷光。
同時垫竞,在修改某個具體角色的時候我們只需要修改對應的具體角色就可以了,不會影響到其他角色蛀序。
如果需要新增角色欢瞪,只要再增加一個具體建造者,并在該建造者中寫好具體細節(jié)的建造部分代碼就OK了徐裸。
2 原理
- 參與者
- Director:導演者遣鼓。擔任這個角色的類調(diào)用具體建造者角色以創(chuàng)建產(chǎn)品對象。一般不與產(chǎn)品類發(fā)生依賴關系重贺。一般來說骑祟,Director被用來封裝程序中易變的部分。
- Builder:抽象建造者气笙。給 出一個抽象接口次企,以規(guī)范產(chǎn)品對象的各個組成成分的建造。一般而言健民,此接口獨立于應用程序的商業(yè)邏輯抒巢。模式中直接創(chuàng)建產(chǎn)品對象的是 ConcreteBuilder。ConcreteBuilder必須實現(xiàn)這個接口所要求的兩種方法:一種是建造方法(buildPart1和 buildPart2)秉犹,另一種是返還結構方法(retrieveResult)蛉谜。一般來說,產(chǎn)品所包含的零件數(shù)目與建造方法的數(shù)目相符崇堵。換言之型诚,有多少零件,就有多少相應的建造方法鸳劳。
- ConcreteBuilder:具體建造者狰贯。它們在應用程序調(diào)用下創(chuàng)建產(chǎn)品的實例。這個角色要完成的任務包括:1.實現(xiàn)抽象建造者Builder所聲明的接口赏廓,給出一步一步地完成創(chuàng)建產(chǎn)品實例的操作涵紊。2.在建造過程完成后,提供產(chǎn)品的實例幔摸。
- Product:產(chǎn)品摸柄。產(chǎn)品便是建造中的復雜對象。一般來說既忆,一個系統(tǒng)中會有多于一個的產(chǎn)品類驱负,而且這些產(chǎn)品類并不一定有共同的接口,而完全可以是不相關聯(lián)的患雇。
導演者角色是與客戶端打交道的角色跃脊。導演者將客戶端創(chuàng)建產(chǎn)品的請求劃分為對各個零件的建造請求,再將這些請求委派給具體建造者角色苛吱。具體建造者角色是做具體建造工作的酪术,但是卻不為客戶端所知。
一般來說翠储,每有一個產(chǎn)品類拼缝,就有一個相應的具體建造者類。這些產(chǎn)品應當有一樣數(shù)目的零件彰亥,而每有一個零件就相應地在所有的建造者角色里有一個建造方法咧七。
2.1 uml圖
-
類圖
- 時序圖
客戶端負責創(chuàng)建導演者和具體建造者對象。然后任斋,客戶端把具體建造者對象交給導演者继阻,導演者操作具體建造者,開始創(chuàng)建產(chǎn)品废酷。當產(chǎn)品完成后瘟檩,建造者把產(chǎn)品返還給客戶端。
把創(chuàng)建具體建造者對象的任務交給客戶端而不是導演者對象澈蟆,是為了將導演者對象與具體建造者對象的耦合變成動態(tài)的墨辛,從而使導演者對象可以操縱數(shù)個具體建造者對象中的任何一個。
2.2 代碼示例
Director代碼示例
public class Director {
/**
* 持有當前需要使用的建造器對象
*/
private Builder builder;
/**
* 構造方法趴俘,傳入建造器對象
* @param builder 建造器對象
*/
public Director(Builder builder){
this.builder = builder;
}
/**
* 產(chǎn)品構造方法睹簇,負責調(diào)用各個零件建造方法
*/
public void construct(){
builder.buildPart1();
builder.buildPart2();
}
}
Builder代碼示例
public interface Builder {
void buildPart1();
void buildPart2();
Product retrieveResult();
}
ConcreteBuilder代碼示例
public class ConcreteBuilder implements Builder {
private Product product = new Product();
/**
* 產(chǎn)品零件建造方法1
*/
@Override
public void buildPart1() {
//構建產(chǎn)品的第一個零件
product.setPart1("編號:9527");
}
/**
* 產(chǎn)品零件建造方法2
*/
@Override
public void buildPart2() {
//構建產(chǎn)品的第二個零件
product.setPart2("名稱:XXX");
}
/**
* 產(chǎn)品返還方法
*/
@Override
public Product retrieveResult() {
return product;
}
}
Product代碼示例
public class Product {
/**
* 定義一些關于產(chǎn)品的操作
*/
private String part1;
private String part2;
public String getPart1() {
return part1;
}
public void setPart1(String part1) {
this.part1 = part1;
}
public String getPart2() {
return part2;
}
public void setPart2(String part2) {
this.part2 = part2;
}
}
調(diào)用示例
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.retrieveResult();
System.out.println(product.getPart1());
System.out.println(product.getPart2());
}
運行結果
編號:9527
名稱:XXX
2.3 優(yōu)缺點
- 優(yōu)點
- 客戶端不必知道產(chǎn)品內(nèi)部組成的細節(jié)奏赘,將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對象太惠。
- 用戶使用不同的具體建造者即可得到不同的產(chǎn)品對象 磨淌。
- 可以更加精細地控制產(chǎn)品的創(chuàng)建過程 。
- 增加新的具體建造者無須修改原有類庫的代碼凿渊,指揮者類針對抽象建造者類編程梁只,系統(tǒng)擴展方便,符合“開閉原則”埃脏。
- 缺點
建造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點搪锣,其組成部分相似,如果產(chǎn)品之間的差異性很大彩掐,則不適合使用建造者模式构舟,因此其使用范圍受到一定的限制。
如果產(chǎn)品的內(nèi)部變化復雜佩谷,可能會導致需要定義很多具體建造者類來實現(xiàn)這種變化旁壮,導致系統(tǒng)變得很龐大。
3 適用場景
在以下情況下可以使用建造者模式:
需要生成的產(chǎn)品對象有復雜的內(nèi)部結構谐檀,這些產(chǎn)品對象通常包含多個成員屬性抡谐。
需要生成的產(chǎn)品對象的屬性相互依賴,需要指定其生成順序桐猬。
對象的創(chuàng)建過程獨立于創(chuàng)建該對象的類麦撵。在建造者模式中引入了指揮者類,將創(chuàng)建過程封裝在指揮者類中溃肪,而不在建造者類中免胃。
隔離復雜對象的創(chuàng)建和使用,并使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品惫撰。
4 與其他模式的關系
4.1 建造者模式與策略模式的區(qū)別
建造者模式在結構上很接近于策略模式羔沙,事實上建造者模式是策略模式的一種特殊情況。
二者的區(qū)別在于用意不同厨钻。
建造者模式作用于客戶端一點一點的建造新的對象扼雏。不同類型的具體建造者雖然都擁有相同的接口,但是他們所創(chuàng)建出來的對象則可能完全不同夯膀。
而策略模式的目的是為算法提供抽象的接口诗充。一個具體策略類把一個算法包裝到一個對象里面,而不同額具體策略對象為一種一般性的服務提供不同的實現(xiàn)诱建。
4 總結
在建造者模式的結構中引入了一個Director類蝴蜓,該類的作用主要有兩個:一方面它隔離了客戶與生產(chǎn)過程;另一方面它負責控制產(chǎn)品的生成過程。Director針對抽象建造者編程茎匠,客戶端只需要知道具體建造者的類型格仲,即可通過Director類調(diào)用建造者的相關方法,返回一個完整的產(chǎn)品對象汽抚。
建造者模式分成兩個很重要的部分:
1. 一個部分是Builder接口抓狭,這里是定義了如何構建各個部件伯病,也就是知道每個部件功能如何實現(xiàn)造烁,以及如何裝配這些部件到產(chǎn)品中去;
2. 另外一個部分是Director午笛,Director是知道如何組合來構建產(chǎn)品惭蟋,也就是說Director負責整體的構建算法,而且通常是分步驟地來執(zhí)行药磺。
不管如何變化告组,建造模式都存在這么兩個部分,一個部分是部件構造和產(chǎn)品裝配癌佩,另一個部分是整體構建的算法木缝。認識這點是很重要的,因為在建造模式中围辙,強調(diào)的是固定整體構建的算法我碟,而靈活擴展和切換部件的具體構造和產(chǎn)品裝配的方式。
再直白點說姚建,建造模式的重心在于分離構建算法和具體的構造實現(xiàn)矫俺,從而使得構建算法可以重用。具體的構造實現(xiàn)可以很方便地擴展和切換掸冤,從而可以靈活地組合來構造出不同的產(chǎn)品對象厘托。
參考書籍及文章
1.《Java與模式》,電子工業(yè)出版社稿湿,閻宏
- 《大話設計模式》铅匹,清華大學出版社,程杰
- 《設計模式——可復用面向?qū)ο筌浖幕A》饺藤,機械工業(yè)出版社包斑,Erich Gamma,Richard Helm策精,Ralph Johnson舰始,John Vlissides
- 《23種設計模式(4):建造者模式》, https://blog.csdn.net/zhengzhb/article/details/7375966
- 《圖說設計模式》咽袜,https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/builder.html