做這么久的項(xiàng)目,卻沒有總結(jié)的習(xí)慣消别。再這樣下去,注定成不了好的程序員
什么是單例 :
Ensure a class only has one instance,and provide a global point of access to凌净。它的主要特點(diǎn)不是根據(jù)客戶程序調(diào)用生成一個(gè)新的實(shí)例,而是控制某個(gè)類型的實(shí)例數(shù)量-唯一一個(gè)屋讶。(《設(shè)計(jì)模式-基于C#的工程化實(shí)現(xiàn)及擴(kuò)展》冰寻,王翔)。也就是說皿渗,單例模式就是保證在整個(gè)應(yīng)用程序的生命周期中斩芭,在任何時(shí)刻,被指定的類只有一個(gè)實(shí)例乐疆,并為客戶程序提供一個(gè)獲取該實(shí)例的全局訪問點(diǎn)划乖。
特點(diǎn):
1,一個(gè)類只能有一個(gè)實(shí)例诀拭;
2迁筛,自己創(chuàng)建這個(gè)實(shí)例;
3,整個(gè)系統(tǒng)都要使用這個(gè)實(shí)例细卧。
蘋果官方單例代碼:具體點(diǎn)擊鏈接
#import
'''
/* Singleton.h */
#import <Foundation/Foundation.h>
@interfaceSingleton:NSObject
+(Singleton*)instance;
@end
/* Singleton.m */
#import "Singleton.h"
staticSingleton*instance=nil;
@implementationSingleton
+(Singleton*)instance
{
if(!instance)
{
instance=[[superallocWithZone:NULL]init];
}
returnin stance;
}
+(id)allocWithZone:(NSZone*)zone
{
return [self instance];
}
-(id)copyWithZone:(NSZone*)zone
{
return self;
}
-(id)init{
if(instance)
{
return instance;
}
self=[super init];
return self;
}
-(id)retain{
return self;
}
-(oneway void)release
{
// Do nothing
}
-(id)autorelease{
return self;
}
-(NSUInteger)retainCount
{
return NSUIntegerMax;
}
@end
為什么用單例:
單例的意圖是為了保證一個(gè)類只有一個(gè)實(shí)例尉桩,并提供訪問它的唯一全局訪問點(diǎn)。之前一直在想贪庙,如果要完成這樣的功能蜘犁,其實(shí)全局變量也可以做到,不是嗎止邮?只要一個(gè)全局變量这橙,然后在各個(gè)需要的地方調(diào)用這個(gè)全局變量即可,必要的時(shí)候可以extern导披,一樣也可以完成這樣的功能屈扎。那么,為什么不直接使用全局變量撩匕,而要搞一個(gè)單例出來鹰晨?單例到底比全局變量好在哪兒?首先止毕,全局變量不能保證全局只有一個(gè)類的實(shí)例模蜡,你完全可以聲明同一個(gè)類的多個(gè)實(shí)例。當(dāng)然扁凛,如果你注意一點(diǎn)忍疾,那么用全局方法保證全局只有一個(gè)該類的實(shí)例還是可以做到的,但你得很注意谨朝,讓自己不要在其他地方聲明多一個(gè)實(shí)例卤妒。而單例卻可以輕松的做到這一點(diǎn),并能保證全局只有一個(gè)該類的實(shí)例可被訪問叠必。其次荚孵,相對(duì)來說,使用單例時(shí)纬朝,代碼會(huì)顯得優(yōu)雅一些收叶。
單例模式與全局變量的詳細(xì)比較
單例模式的其他應(yīng)用場(chǎng)景
什么時(shí)候用單例
單例的使用主要是在需要保證全局只有一個(gè)實(shí)例可以被訪問的情況,比如[系統(tǒng)]日志的輸出共苛、[操作系統(tǒng)]的任務(wù)管理器等判没。
一些細(xì)節(jié)
通常,我們看到的單例類沒有析構(gòu)函數(shù)隅茎,那么new出來的[空間]是怎么釋放的呢澄峰?一般有2種做法,一種是不做任何操作辟犀,等最后程序結(jié)束時(shí)操作系統(tǒng)回收[資源]俏竞;另外一種是另外搞一個(gè)函數(shù)或者類,來處理delete操作。對(duì)于像我這樣的初級(jí)使用學(xué)者魂毁,還是選擇第一種更方便玻佩,第二種相對(duì)來說需要考慮更多一些。
兩種經(jīng)典的多線程單例寫法
一席楚、經(jīng)典模式:
publicclass Singleton
{
privatestatic Singleton instance;
private Singleton()
{}
publicstatic Singleton GetInstance()
{
if(instance==null)
{
instance=new Singleton();
}
return instance;
}
解析如下:
1)首先咬崔,該Singleton的構(gòu)造函數(shù)必須是私有的,以保證客戶程序不會(huì)通過new()操作產(chǎn)生一個(gè)實(shí)例烦秩,達(dá)到實(shí)現(xiàn)單例的目的垮斯;
2)因?yàn)殪o態(tài)變量的生命周期跟整個(gè)應(yīng)用程序的生命周期是一樣的,所以可以定義一個(gè)私有的靜態(tài)全局變量instance來保存該類的唯一實(shí)例只祠;
3)必須提供一個(gè)全局函數(shù)訪問獲得該實(shí)例兜蠕,并且在該函數(shù)提供控制實(shí)例數(shù)量的功能,即通過if語句判斷instance是否已被實(shí)例化抛寝,如果沒有則可以同new()創(chuàng)建一個(gè)實(shí)例牺氨;否則,直接向客戶返回一個(gè)實(shí)例墩剖。
在這種經(jīng)典模式下,沒有考慮線程并發(fā)獲取實(shí)例問題夷狰,即可能出現(xiàn)兩個(gè)線程同時(shí)獲取instance實(shí)例岭皂,且此時(shí)其為null時(shí),就會(huì)出現(xiàn)兩個(gè)線程分別創(chuàng)建了instance沼头,違反了單例規(guī)則爷绘。因此,需對(duì)上面代碼修改进倍。
二土至、多線程下的單例模式
1、Lazy模式
publicclass Singleton
{
privatestatic Singleton instance;
private Singleton()
{
}
publicstatic Singleton GetInstance()
{
if(instance==null)
{
instance=new Singleton();
}
return instance;
}
}
上述代碼使用了雙重鎖方式較好地解決了多線程下的單例模式實(shí)現(xiàn)猾昆。先看內(nèi)層的if語句塊陶因,使用這個(gè)語句塊時(shí),先進(jìn)行加鎖操作垂蜗,保證只有一個(gè)線程可以訪問該語句塊楷扬,進(jìn)而保證只創(chuàng)建了一個(gè)實(shí)例。再看外層的if語句塊贴见,這使得每個(gè)線程欲獲取實(shí)例時(shí)不必每次都得加鎖烘苹,因?yàn)橹挥袑?shí)例為空時(shí)(即需要?jiǎng)?chuàng)建一個(gè)實(shí)例),才需加鎖創(chuàng)建片部,若果已存在一個(gè)實(shí)例镣衡,就直接返回該實(shí)例,節(jié)省了性能開銷。
2廊鸥、餓漢模式
這種模式的特點(diǎn)是自己主動(dòng)實(shí)例望浩。
publicclass Singleton
{
privatestatic Singleton instance;
privatestaticobject _lock=newobject();
private Singleton()
{
}
publicstatic Singleton GetInstance()
{
if(instance==null)
{
lock(_lock)
{
if(instance==null)
{
instance=new Singleton();
}
}
}
return instance;
}
}
上面使用的readonly關(guān)鍵可以跟static一起使用,用于指定該常量是類別級(jí)的黍图,它的初始化交由靜態(tài)構(gòu)造函數(shù)實(shí)現(xiàn)曾雕,并可以在運(yùn)行時(shí)編譯。在這種模式下助被,無需自己解決線程安全性問題剖张,CLR會(huì)給我們解決。由此可以看到這個(gè)類被加載時(shí)揩环,會(huì)自動(dòng)實(shí)例化這個(gè)類搔弄,而不用在第一次調(diào)用GetInstance()后才實(shí)例化出唯一的單例對(duì)象。