iOS設計模式(一)原型模式绎狭、工廠模式细溅、抽象工廠模式、建造者模式儡嘶、單例模式

原型設計模式

在面向對象的應用程序中喇聊,有些對象的創(chuàng)建成本比較高。比如一些數據模型蹦狂,如果有十幾二十個屬性誓篱,而需要創(chuàng)建的對象和已有的對象只有幾項數據不同,這時我們可以復制原有對象凯楔,并做輕微的改動窜骄,事情就變得相對簡單了,使用這種復制操作的模式便是原型模式摆屯。

原型模式類圖:


原型模式類圖.png

圖中的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)建對象,在給予類變更返回哪一種對象這一點上有更多的靈活性矗蕊。

工廠模式類圖


工廠模式類圖.png

圖中的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é)工程示例

抽象工廠模式

同樣的電子產品來說窥摄,崭放。

抽象工廠類圖


抽象工廠類圖.png

圖中的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)建者的模式轩触,客戶端直接使用指導者的指導方式進行對象的生成。使用這種構建與它的表現分離模式我們稱為建造者模式家夺,也稱為生成器模式拉馋。

建造者模式類圖:


建造者模式類圖.png

圖中的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的登錄用戶信息也可以設計為單例模式,持有用戶奕翔,信息共享裕寨。

單例模式類圖


單例模式類圖.png

圖中的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é)工程示例

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市驾窟,隨后出現的幾起案子庆猫,更是在濱河造成了極大的恐慌,老刑警劉巖绅络,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件月培,死亡現場離奇詭異,居然都是意外死亡恩急,警方通過查閱死者的電腦和手機杉畜,發(fā)現死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衷恭,“玉大人此叠,你說我怎么就攤上這事∷嬷椋” “怎么了灭袁?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵猬错,是天一觀的道長。 經常有香客問我茸歧,道長倦炒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任软瞎,我火速辦了婚禮逢唤,結果婚禮上勤哗,老公的妹妹穿的比我還像新娘牙咏。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布芙代。 她就那樣靜靜地躺著,像睡著了一般盖彭。 火紅的嫁衣襯著肌膚如雪纹烹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天召边,我揣著相機與錄音铺呵,去河邊找鬼。 笑死隧熙,一個胖子當著我的面吹牛片挂,可吹牛的內容都是我干的。 我是一名探鬼主播贞盯,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼音念,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了躏敢?” 一聲冷哼從身側響起闷愤,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎件余,沒想到半個月后讥脐,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡啼器,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年旬渠,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片端壳。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡告丢,死狀恐怖,靈堂內的尸體忽然破棺而出更哄,到底是詐尸還是另有隱情芋齿,我是刑警寧澤腥寇,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站觅捆,受9級特大地震影響赦役,放射性物質發(fā)生泄漏。R本人自食惡果不足惜栅炒,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一掂摔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赢赊,春花似錦乙漓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至玩讳,卻和暖如春涩蜘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背熏纯。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工同诫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人樟澜。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓误窖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秩贰。 傳聞我的和親對象是個殘疾皇子霹俺,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354