【设计模式】五、单例模式(独一无二的对象)
一、概述:
有一些對(duì)象我們只需要一個(gè),比方說(shuō):線(xiàn)程池(threadpool)、緩存(cache)、對(duì)話(huà)框、處理偏好設(shè)置和注冊(cè)表對(duì)象、日志對(duì)象、充當(dāng)打印機(jī)、顯卡等設(shè)備的驅(qū)動(dòng)程序的對(duì)象。事實(shí)上這些對(duì)象只需要一個(gè)實(shí)例,如果制造出多個(gè)實(shí)例就會(huì)導(dǎo)致很多問(wèn)題發(fā)生。(利用靜態(tài)類(lèi)變量、靜態(tài)方法和適當(dāng)?shù)脑L問(wèn)修飾符的確也可以做到只存在一個(gè)實(shí)例。)
蘇格拉底誘導(dǎo)式回答:(參考《Head First 設(shè)計(jì)模式》)
| 如何創(chuàng)建一個(gè)對(duì)象? | new MyObject() |
| 萬(wàn)一另外一個(gè)對(duì)象想創(chuàng)Myobject會(huì)怎樣?可以再次new MyObject嗎? | 是的,當(dāng)然可以。 |
| 所以一旦有一個(gè)類(lèi),我們是否都能多次的實(shí)例化它? | 如果是公開(kāi)的類(lèi) 就可以 |
| 如果不是的話(huà),會(huì)怎樣? | 如果不是公開(kāi)的類(lèi),只有同一個(gè)包內(nèi)的類(lèi)可以實(shí)例化它,但是仍可以實(shí)例化它很多次 |
| 可以這么做嗎? public Myclass {private Myclass(){} }? | ?我沒(méi)想過(guò),但是這是合法的定義,有一定的道理。 |
| ?怎么說(shuō)呢? | ?我認(rèn)為含有私有的構(gòu)造器類(lèi)不能唄實(shí)例化。 |
| ?又可以使用私有的構(gòu)造器對(duì)象嗎? | ?恩,我想Myclass內(nèi)的代碼是唯一能調(diào)用此構(gòu)造器的代碼,但是這又不太合乎常理。 |
| ?WHY? | ?因?yàn)橹挥蠱yclass的實(shí)例才能調(diào)用Myclass的構(gòu)造器,但是因?yàn)闆](méi)有其他類(lèi)能夠?qū)嵗疢yclass,所以我們得不到這樣的實(shí)例。 |
| ?嘿,我有個(gè)想法。 你認(rèn)為如何? public Myclass {public static MyClass getInstance(){} }MyClass有一個(gè)靜態(tài)方法,我們可以這樣調(diào)用這個(gè)方法: MyClas.getInstance(); | ? |
| ?為何調(diào)用的時(shí)候用MyCLass類(lèi)名,而不是對(duì)象名。 | ?因?yàn)間etInstance是類(lèi)方法,是一個(gè)靜態(tài)方法,你需要使用類(lèi)名。 |
| ?有意思,假如把這些合在一起“是否”就可以初始化一個(gè)MyClass? public MyClass {private MyClass(){}public static Myclass getInstance(){return new MyClass();} }? | 當(dāng)然可以? |
| ?好了,你能想出第二種實(shí)例化對(duì)象的方式嗎? | ?MyClass.getInstance(); |
| ?你能夠完成代碼是MyClass只有一個(gè)實(shí)例被產(chǎn)生嗎? | ?恩,大概可以吧。。。。 |
?
單例模式優(yōu)點(diǎn)
單例模式缺點(diǎn)
二、在IOS中的應(yīng)用
單例模式在iOS開(kāi)發(fā)中的使用還是蠻多的,許多Foundation、Cocoa和UIKit中的類(lèi)都實(shí)現(xiàn)了單例模式,比如應(yīng)用程序本身UIApplication、文件操作類(lèi)NSFileManager、消息中心NSNotificitonCenter等系統(tǒng)都已經(jīng)給我們實(shí)現(xiàn)單例,我們只需要使用就好了。在iOS中使用單例模式要使用類(lèi)方法,通過(guò)類(lèi)方法返回該類(lèi)的唯一對(duì)象。
在ios中的應(yīng)用主要有以下三種方式
1、
static Singleton *instance = nil;+ (Singleton *)sharedInstance {if (instance == nil) {instance = [[super allocWithZone:NULL] init];}return instance; }+ (id)allocWithZone:(NSZone *)zone {return [[self sharedInstance] retain]; }- (id)copyWithZone:(NSZone *)zone {return self; }- (id)retain {return self; }- (NSUInteger)retainCount {return NSUIntegerMax; //denotes an object that cannot be released }- (void)release {//do nothing }- (id)autorelease {return self; }可以看到這種方式,使用靜態(tài)成員維持了一個(gè)永久存在的對(duì)象,而且覆蓋了alloc方法(alloc方法會(huì)調(diào)用allocWithZone:方法),并且也覆蓋了所有與引用技術(shù)有關(guān)的方法,這都使這個(gè)對(duì)象不會(huì)被銷(xiāo)毀。這樣看上去基本實(shí)現(xiàn)了我們需要的,但是寫(xiě)起來(lái)麻煩不說(shuō),還有很大的一個(gè)問(wèn)題,那就是多線(xiàn)程問(wèn)題,如果是在多線(xiàn)程中那么該種方法就不能保證只產(chǎn)生一個(gè)對(duì)象了。所以這種方式只是介紹一下,并不推薦使用。
2、引入頭文件
程序員都是偷懶的,現(xiàn)在流行使用一個(gè)宏定義來(lái)搞定這許多的事,而且考慮的更加周全。
單例包含以下接口?
+ (MyClass*) sharedInstance;?
+ (void) purgeSharedInstance;
調(diào)用sharedInstance會(huì)創(chuàng)建并返回單例
調(diào)用purgeSharedInstance會(huì)銷(xiāo)毀單例
手動(dòng)調(diào)用alloc也可以保證是單例,你可以這樣調(diào)用
[[MyClass alloc] initWithParam:firstParam secondParam:secondParam];
只是要保證在sharedInstance之前調(diào)用,因?yàn)橹挥幸淮蝿?chuàng)建機(jī)會(huì)。
下面是使用宏的寫(xiě)法“?
MyClass.h: ======================================== #import "SynthesizeSingleton.h" @interface MyClass: SomeSuperclass { ... } SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(MyClass); @end ======================================== MyClass.m: ======================================== #import "MyClass.h" @implementation MyClass SYNTHESIZE_SINGLETON_FOR_CLASS(MyClass); ... @end ========================================開(kāi)源庫(kù)下載地址
3、
iOS在4.0以后推出了block和GCD,這兩個(gè)特性給iOS開(kāi)發(fā)帶來(lái)的很大的便利,也使開(kāi)發(fā)變得更加趣味話(huà)。那么如何通過(guò)GCD+block來(lái)實(shí)現(xiàn)單例模式呢,這主要?dú)w功于dispatch_once(dispatch_once_t *predicate, ^(void)block)這個(gè)GCD的函數(shù),他有兩個(gè)參數(shù)第一參數(shù)是一個(gè)指向dispatch_once_t類(lèi)型結(jié)構(gòu)體的指針,用來(lái)測(cè)試block是否執(zhí)行完成,該指針?biāo)赶虻慕Y(jié)構(gòu)體必須是全局的或者靜態(tài)的,第二個(gè)參數(shù)是一個(gè)返回值與參數(shù)均為空的block,在block體中進(jìn)行對(duì)象的初始化即可。dispatch_once在程序的生命周期中保證只會(huì)被調(diào)用一次,所以在多線(xiàn)程中也不會(huì)有問(wèn)題。 該種方法使用方法:
?
+ (Singleton *)sharedInstance {static Singleton *instance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{instance = [[Singleton alloc]init];});return instance; }dispatch_once的作用就是執(zhí)行且在整個(gè)程序的聲明周期中,僅執(zhí)行一次某一個(gè)block對(duì)象。簡(jiǎn)直就是為單例而生的嘛。而且,有些我們需要在程序開(kāi)頭初始化的動(dòng)作,如果為了保證其,僅執(zhí)行一次,也可以放到這個(gè)dispatch_once來(lái)執(zhí)行。
然后我們看到它需要一個(gè)斷言來(lái)確定這個(gè)代碼塊是否執(zhí)行,這個(gè)斷言的指針要保存起來(lái),相對(duì)于第一種方法而言,還需要多保存一個(gè)指針。
?
方法簡(jiǎn)介中就說(shuō)的很清楚了:對(duì)于在應(yīng)用中創(chuàng)建一個(gè)初始化一個(gè)全局的數(shù)據(jù)對(duì)象(單例模式),這個(gè)函數(shù)很有用。
如果同時(shí)在多線(xiàn)程中調(diào)用它,這個(gè)函數(shù)將等待同步等待,直至該block調(diào)用結(jié)束。
這個(gè)斷言的指針必須要全局化的保存,或者放在靜態(tài)區(qū)內(nèi)。使用存放在自動(dòng)分配區(qū)域或者動(dòng)態(tài)區(qū)域的斷言,dispatch_once執(zhí)行的結(jié)果是不可預(yù)知的。
?
總結(jié):1.這個(gè)方法可以在創(chuàng)建單例或者某些初始化動(dòng)作時(shí)使用,以保證其唯一性。2.該方法是線(xiàn)程安全的,所以請(qǐng)放心大膽的在子線(xiàn)程中使用。(前提是你的dispatch_once_t?onceToken
對(duì)象必須是全局或者靜態(tài)對(duì)象。這一點(diǎn)很重要,如果不能保證這一點(diǎn),也就不能保證該方法只會(huì)被執(zhí)行一次。)
?
參考博客:
水滴石穿 Keeping faith.??????--- wtlucky's Blog
?
轉(zhuǎn)載于:https://www.cnblogs.com/ymonke/p/3513668.html
總結(jié)
以上是生活随笔為你收集整理的【设计模式】五、单例模式(独一无二的对象)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 传智168期JavaEE struts2
- 下一篇: 用Python 操作Web 前端 基础