一、概念
1、建造者模式的動(dòng)機(jī)
? 沒有人買車會(huì)只買一個(gè)輪胎或者方向盤抵乓,大家買的都是一輛包含輪胎、方向盤和發(fā)動(dòng)機(jī)等多個(gè)部件的完整汽車。如何將這些部件組裝成一輛完整的汽車并返回給用戶灾炭,這是建造者模式需要解決的問題茎芋。
2、建造者模式的定義
? 建造者模式(Builder Pattern):將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離蜈出,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示田弥。建造者模式是一種對(duì)象創(chuàng)建型模式。
? 建造者模式又稱為生成器模式铡原,它是一種較為復(fù)雜偷厦、使用頻率也相對(duì)較低的創(chuàng)建型模式。建造者模式為客戶端返回的不是一個(gè)簡(jiǎn)單的產(chǎn)品燕刻,而是一個(gè)由多個(gè)部件組成的復(fù)雜產(chǎn)品只泼。
3、建造者模式的4個(gè)角色
1)Builder(抽象建造者):它為創(chuàng)建一個(gè)產(chǎn)品Product對(duì)象的各個(gè)部件指定抽象接口卵洗,在該接口中一般聲明兩類方法请唱,一類方法是buildPartX(),它們用于創(chuàng)建復(fù)雜對(duì)象的各個(gè)部件过蹂;另一類方法是getResult()十绑,它們用于返回復(fù)雜對(duì)象。Builder既可以是抽象類酷勺,也可以是接口本橙。
2)ConcreteBuilder(具體建造者):它實(shí)現(xiàn)了Builder接口,實(shí)現(xiàn)各個(gè)部件的具體構(gòu)造和裝配方法鸥印,定義并明確它所創(chuàng)建的復(fù)雜對(duì)象勋功,也可以提供一個(gè)方法返回創(chuàng)建好的復(fù)雜產(chǎn)品對(duì)象。
3)Product(產(chǎn)品角色):它是被構(gòu)建的復(fù)雜對(duì)象库说,包含多個(gè)組成部件,具體建造者創(chuàng)建該產(chǎn)品的內(nèi)部表示并定義它的裝配過程片择。
4)Director(指揮者):指揮者又稱為導(dǎo)演類潜的,它負(fù)責(zé)安排復(fù)雜對(duì)象的建造次序,指揮者與抽象建造者之間存在關(guān)聯(lián)關(guān)系字管,可以在其construct()建造方法中調(diào)用建造者對(duì)象的部件構(gòu)造與裝配方法啰挪,完成復(fù)雜對(duì)象的建造。
4嘲叔、建造者模式與抽象工廠模式的區(qū)別
? 建造者模式與抽象工廠模式有點(diǎn)相似亡呵,但是建造者模式返回一個(gè)完整的復(fù)雜產(chǎn)品,而抽象工廠模式返回一系列相關(guān)的產(chǎn)品硫戈。在抽象工廠模式中锰什,客戶端通過選擇具體工廠來生成所需對(duì)象,而在建造者模式中,客戶端通過指定具體建造者類型并指導(dǎo)Director類如何去生成對(duì)象汁胆,側(cè)重于一步步構(gòu)造一個(gè)復(fù)雜對(duì)象梭姓,然后將結(jié)果返回。如果將抽象工廠模式看成一個(gè)汽車配件生產(chǎn)廠嫩码,生成不同類型的汽車配件誉尖,那么建造者模式就是一個(gè)汽車組裝廠,通過對(duì)配件進(jìn)行組裝返回一輛完整的汽車铸题。
5铡恕、結(jié)構(gòu)圖
二、示例
1)首先創(chuàng)建一個(gè)Phone類丢间,是產(chǎn)品角色没咙;
2)然后創(chuàng)建一個(gè)PhoneBuilder協(xié)議,是抽象建造者千劈,是個(gè)接口祭刚;
3)然后創(chuàng)建HuaWeiBuilder類和IphoneBuilder類,兩個(gè)類都遵循PhoneBuilder協(xié)議墙牌,實(shí)現(xiàn)協(xié)議的接口涡驮,是具體建造者;
4)最后創(chuàng)建PhoneDirector類喜滨,是指揮者捉捅。
具體代碼如下:
Phone類:
@interface Phone : NSObject
@property(nonatomic, copy) NSString *cpu;
@property(nonatomic, copy) NSString *screen;
@property(nonatomic, copy) NSString *camera;
@property(nonatomic, copy) NSString *system;
@end
@implementation Phone
@end
PhoneBuilder協(xié)議:
@protocol PhoneBuilder <NSObject>
@property(nonatomic, strong) Phone *phone;
- (void)buildCPU;
- (void)buildScreen;
- (void)buildCamera;
- (void)buildSystem;
@end
typedef id<PhoneBuilder> PhoneBuilder; //重新命名類型,方便后面使用
HuaWeiBuilder類:
@interface HuaWeiBuilder : NSObject<PhoneBuilder>
@end
@implementation HuaWeiBuilder
@synthesize phone = _phone;
- (instancetype)init
{
self = [super init];
if (self) {
_phone = [Phone new];
}
return self;
}
- (void)buildCPU {
_phone.cpu = @"麒麟處理器";
}
- (void)buildScreen {
_phone.screen = @"京東方屏幕";
}
- (void)buildCamera {
_phone.camera = @"萊卡攝像頭";
}
- (void)buildSystem {
_phone.system = @"安卓系統(tǒng)";
}
@end
IphoneBuilder類:
@interface IphoneBuilder : NSObject<PhoneBuilder>
@end
@implementation IphoneBuilder
@synthesize phone = _phone;
- (instancetype)init
{
self = [super init];
if (self) {
_phone = [Phone new];
}
return self;
}
- (void)buildCPU {
_phone.cpu = @"A系列處理器";
}
- (void)buildScreen {
_phone.screen = @"三星屏幕";
}
- (void)buildCamera {
_phone.camera = @"Sony攝像頭";
}
- (void)buildSystem {
_phone.system = @"iOS系統(tǒng)";
}
@end
PhoneDirector類:
@interface PhoneDirector : NSObject
- (Phone *)constructWithBuilder:(PhoneBuilder)builder;
@end
@implementation PhoneDirector
- (Phone *)constructWithBuilder:(PhoneBuilder)builder {
[builder buildCPU];
[builder buildScreen];
[builder buildCamera];
[builder buildSystem];
return builder.phone;
}
@end
運(yùn)行代碼:
- (void)viewDidLoad {
[super viewDidLoad];
PhoneDirector *director = [PhoneDirector new];
HuaWeiBuilder *huaWeiBuilder = [HuaWeiBuilder new];
IphoneBuilder *iPhoneBuilder = [IphoneBuilder new];
Phone *huaWeiPhone = [director constructWithBuilder:huaWeiBuilder];
Phone *iphone = [director constructWithBuilder:iPhoneBuilder];
NSLog(@"HuaWeiPhone:cpu = %@, screen = %@, camera = %@, system = %@", huaWeiPhone.cpu, huaWeiPhone.screen, huaWeiPhone.camera, huaWeiPhone.system);
NSLog(@"iPhone:cpu = %@, screen = %@, camera = %@, system = %@", iphone.cpu, iphone.screen, iphone.camera, iphone.system);
}
打印結(jié)果:
HuaWeiPhone:cpu = 麒麟處理器, screen = 京東方屏幕, camera = 萊卡攝像頭, system = 安卓系統(tǒng)
iPhone:cpu = A系列處理器, screen = 三星屏幕, camera = Sony攝像頭, system = iOS系統(tǒng)
三虽风、總結(jié)
? 建造者模式的核心在于如何一步步構(gòu)建一個(gè)包含多個(gè)組成部件的完整對(duì)象棒口,使用相同的構(gòu)建過程構(gòu)建不同的產(chǎn)品,在軟件開發(fā)中辜膝,如果我們需要?jiǎng)?chuàng)建復(fù)雜對(duì)象并希望系統(tǒng)具備很好的靈活性和可擴(kuò)展性可以考慮使用建造者模式无牵。
? 在有些情況下,為了簡(jiǎn)化系統(tǒng)結(jié)構(gòu)厂抖,可以將Director和抽象建造者Builder進(jìn)行合并茎毁,在Builder中提供逐步構(gòu)建復(fù)雜產(chǎn)品對(duì)象的construct()方法。
1忱辅、優(yōu)點(diǎn)
1七蜘、在建造者模式中,客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)墙懂,將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦橡卤,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對(duì)象。
2损搬、每一個(gè)具體建造者都相對(duì)獨(dú)立碧库,而與其他的具體建造者無(wú)關(guān)柜与,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產(chǎn)品對(duì)象谈为。由于指揮者類針對(duì)抽象建造者編程旅挤,增加新的具體建造者無(wú)須修改原有類庫(kù)的代碼,系統(tǒng)擴(kuò)展方便伞鲫,符合“開閉原則”粘茄。
3、可以更加精細(xì)地控制產(chǎn)品的創(chuàng)建過程秕脓。將復(fù)雜產(chǎn)品的創(chuàng)建步驟分解在不同的方法中柒瓣,使得創(chuàng)建過程更加清晰,也更方便使用程序來控制創(chuàng)建過程吠架。
2芙贫、缺點(diǎn)
1、建造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點(diǎn)傍药,其組成部分相似磺平,如果產(chǎn)品之間的差異性很大,例如很多組成部分都不相同拐辽,不適合使用建造者模式拣挪,因此其使用范圍受到一定的限制。
2俱诸、如果產(chǎn)品的內(nèi)部變化復(fù)雜菠劝,可能會(huì)導(dǎo)致需要定義很多具體建造者類來實(shí)現(xiàn)這種變化,導(dǎo)致系統(tǒng)變得很龐大睁搭,增加系統(tǒng)的理解難度和運(yùn)行成本赶诊。
3、適用場(chǎng)景
1园骆、需要生成的產(chǎn)品對(duì)象有復(fù)雜的內(nèi)部結(jié)構(gòu)舔痪,這些產(chǎn)品對(duì)象通常包含多個(gè)成員屬性。
2遇伞、需要生成的產(chǎn)品對(duì)象的屬性相互依賴辙喂,需要指定其生成順序。
3鸠珠、 對(duì)象的創(chuàng)建過程獨(dú)立于創(chuàng)建該對(duì)象的類。在建造者模式中通過引入了指揮者類秋麸,將創(chuàng)建過程封裝在指揮者類中渐排,而不在建造者類和客戶類中。
4灸蟆、隔離復(fù)雜對(duì)象的創(chuàng)建和使用驯耻,并使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品。
4、iOS應(yīng)用舉例
? 比如SDWebImage的SDWebImageDownloader和SDWebImageDownloaderOperation就是director和builder之間的關(guān)系可缚。前者不負(fù)責(zé)具體的下載操作霎迫,只負(fù)責(zé)管理builder,builder負(fù)責(zé)圖片的具體下載帘靡。
Demo地址:iOS-Design-Patterns