原型設計模式
在面向對象的應用程序中喇聊,有些對象的創(chuàng)建成本比較高。比如一些數據模型蹦狂,如果有十幾二十個屬性誓篱,而需要創(chuàng)建的對象和已有的對象只有幾項數據不同,這時我們可以復制原有對象凯楔,并做輕微的改動窜骄,事情就變得相對簡單了,使用這種復制操作的模式便是原型模式摆屯。
原型模式類圖:
圖中的HeroModel類實現了PrototypeProtocold定義的復制接口邻遏,返回自己的實例對象。
HeroModel模型的實現
@implementation HeroModel
- (id)clone {
HeroModel *hero = [[[self class] alloc] init];
hero.name = self.name;
hero.profession = self.profession;
hero.maxHP = self.maxHP;
hero.position = self.position;
return hero;
}
@end
測試
HeroModel *hero = [[HeroModel alloc] init];
hero.name = @"Luxanna Crownguard";
hero.profession = @"Master";
hero.maxHP = @(600);
hero.position = [NSMutableArray arrayWithArray:@[@"mid"]];
HeroModel *hero1 = [hero clone];
hero1.name = @"Brand";
NSLog(@"%@",hero);
NSLog(@"%@",hero1);
//打印輸出
//<HeroModel: 0x100400270> {name: Luxanna Crownguard,,profession: Master,,maxHP: 600,,position: (mid)}
//<HeroModel: 0x1004002f0> {name: Brand,,profession: Master,,maxHP: 600,,position: (mid)}
用原型設計模式實現了簡單的復制功能虐骑,hero和hero1的數據一致准验,只是復制后改動name屬性,便創(chuàng)建了一個全新的HeroModel對象廷没。
注意深拷貝和淺拷貝
在使用原型模式的時候需要注意對象的復制操作糊饱,如上的示例中就存在一定的隱患,在打印之前對原型做如下如下操作
[hero.position addObject:@"support"];
得到打印的結果
<HeroModel: 0x100508c90> {name: Luxanna Crownguard,,profession: Master,,maxHP: 600,,position: (mid,support)}
<HeroModel: 0x100508d10> {name: Brand,,profession: Master,,maxHP: 600,,position: (mid,support)}
可見hero的position內容發(fā)生了改變颠黎,hero1的position也隨之改變了另锋。在對象中如果有指針型變量指向了內存中的某個資源時,在復制的時候只復制了指針盏缤,那么改變了原型砰蠢,副本相應的內容也跟著發(fā)生了改變,在這里我們就需要使用深拷貝唉铜,做好實際資源的復制潭流。如上的實現可改為:
HeroModel *hero = [[[self class] alloc] init];
hero.name = self.name;
hero.profession = self.profession;
hero.maxHP = self.maxHP;
hero.position = [NSMutableArray arrayWithArray:self.position];
在Cocoa Touch框架也為NSObject的派生類提供了實現復制的協議灰嫉,使用方法只需遵守<NSCopying>協議,并實現 - (id)copyWithZone:(nullable NSZone *)zone 方法浑厚。
本節(jié)工程示例
工廠模式
在創(chuàng)建一些具有相同屬性的不同對象的時候钳幅,我們可以定制統(tǒng)一的接口行為類,讓其子類來指定所生成的具體對象诬乞。例如需要生產蘋果手機產品震嫉,統(tǒng)一定制生產的”協議“牡属,自己可以由自己下面的不同的代工廠生產具體的產品湃望,SE的代工廠生產SE,X生產X瞳浦。當然需要生產何種產品時交由具體的代工廠來生產废士。使用工廠模式創(chuàng)建對象比直接創(chuàng)建對象,在給予類變更返回哪一種對象這一點上有更多的靈活性矗蕊。
工廠模式類圖
圖中的IPhoneGenerator類定義了返回IPhone對象的接口氢架,其兩個子類重載了接口方法,以返回IPhone的實例卿操。
IPhoneSEGenerator的實現
- (IPhone *)creatIPhone
{
return [[IPhoneSE alloc] init];
}
IPhoneXGenerator的實現
- (IPhone *)creatIPhone
{
return [[IPhoneX alloc] init];
}
客戶端創(chuàng)建
IPhoneGenerator *generator_X = [[IPhoneXGenerator alloc] init];
IPhoneGenerator *generator_SE = [[IPhoneSEGenerator alloc] init];
IPhone *iphone_X = [generator_X creatIPhone];
IPhone *iphone_SE = [generator_SE creatIPhone];
其中具體生產哪種類型的Iphone由具體的創(chuàng)建者來決定生產害淤。
本節(jié)工程示例
抽象工廠模式
同樣的電子產品來說窥摄,崭放。
抽象工廠類圖
圖中的IBrandingGenerator類定義了兩個返回IPhone對象的接口莹菱,其兩個子類重載接口方法道伟,以返回IPhone的實例使碾。
BrandingGenerator工廠的實現票摇,在頭文件中定義創(chuàng)建APPLE系列還是SAMSUNG系列,具體工廠會依據定義來生成:
+ (BrandingGenerator *)generator
{
#if defined (USS_APPLE)
return [[AppleBrandingGenerator alloc] init];
#elif defined (USS_SAMSUNG)
return [[SamsungBrandingGenerator alloc] init];
#else
return nil;
#endif
}
- (TV *)generatorTV
{
return nil;
}
- (Phone *)generatorPhone
{
return nil;
}
- (Computer *)generatorComputer
{
return nil;
}
AppleBrandingGenerator工廠的實現
- (TV *)generatorTV
{
return [[AppleTV alloc] init];
}
- (Phone *)generatorPhone
{
return [[ApplePhone alloc] init];
}
- (Computer *)generatorComputer
{
return [[AppleComputer alloc] init];
}
SamsungBrandingGenerator工廠的實現
- (TV *)generatorTV
{
return [[SamsungTV alloc] init];
}
- (Phone *)generatorPhone
{
return [[SamsungPhone alloc] init];
}
- (Computer *)generatorComputer
{
return [[SamsungComputer alloc] init];
}
客戶端創(chuàng)建
BrandingGenerator *generator = [BrandingGenerator generator];
TV *tv = [generator generatorTV];
Phone *phone = [generator generatorPhone];
Computer *computer = [generator generatorComputer];
在這種模式下如果需要擴展產品盆色,可在工廠父類中新增接口來支持。另外還可以新增產品系列的支持祟剔。
本節(jié)工程示例
工廠方法和抽象工廠
相比較之下隔躲,這兩種方式在創(chuàng)建對象時物延,都不讓客戶端知曉到底返回了什么確切的具體對象宣旱。工廠模式是通過類繼承來創(chuàng)建的抽象產品叛薯,并且只能創(chuàng)建單一品種浑吟,需要新增子類創(chuàng)建者重載工廠方法來支持新的產品創(chuàng)建。而抽象工廠模式是通過對象組合來創(chuàng)建抽象產品组力,可以實現多系列的產品創(chuàng)建,需要在父類新增接口來支持新的產品創(chuàng)建抖拴。
建造者模式
有些對象的創(chuàng)建比較復雜燎字,一個對象包含很多個部件的組成部分,我們將構建過程拆分成指導者-創(chuàng)建者的模式轩触,客戶端直接使用指導者的指導方式進行對象的生成。使用這種構建與它的表現分離模式我們稱為建造者模式家夺,也稱為生成器模式拉馋。
建造者模式類圖:
圖中的HeroModel類實現了PrototypeProtocold定義的復制接口日川,返回自己的實例對象。
HeroModel模型的實現
@interface ComputerBuilder ()
@property (nonatomic, strong) Computer *computer;
@end
@implementation ComputerBuilder
- (instancetype)init
{
if (self = [super init]) {
_computer = [[Computer alloc] init];
}
return self;
}
// 構建CPU
- (ComputerBuilder *)buildCpu:(NSString *)cpu
{
[_computer setCpu:cpu];
return self;
}
// 構建顯卡
- (ComputerBuilder *)buildDisplay:(NSString *)display
{
[_computer setDisplay:display];
return self;
}
// 構建主板
- (ComputerBuilder *)buildMainboard:(NSString *)mainboard
{
[_computer setMainBoard:mainboard];
return self;
}
// 構建
- (Computer *)build
{
return _computer;
}
@end
使用這種多個步驟龄句、多種方式構建對象分歇,在最后一步返回產品,這個過程比單一創(chuàng)建更容易管理與復用欧漱。
本節(jié)工程示例
單例模式
在我們開發(fā)的應用中职抡,那些只能共享而不能復制的資源,也就是在系統(tǒng)只需存在一份實例误甚,我們可以使用單例模式缚甩。例如iOS中的UIApplication、NSUSerDefaults中使用單例模式窑邦,只存在單一的訪問點擅威。例如我們app的登錄用戶信息也可以設計為單例模式,持有用戶奕翔,信息共享裕寨。
單例模式類圖
圖中的sharedInstance類定義了返回自身單例對象的接口。
Singleton的實現
@implementation Singleton
//線程安全(多線程下可以運用)
static Singleton* instance = nil;
+(instancetype)sharedInstance{
static dispatch_once_t once;
dispatch_once(&once, ^{
instance = [[Singleton alloc] init];
});
return instance;
}
//當我們調用alloc時候回調改方法(保證唯一性)
+(id)allocWithZone:(struct _NSZone *)zone{
if(instance == nil){
static dispatch_once_t once;
dispatch_once(&once, ^{
instance = [super allocWithZone:zone];
});
}
return instance;
}
@end
通過GCD來保證線程安全派继,重寫allocWithZone保證不會返回新的實例宾袜。
本節(jié)工程示例