Android開(kāi)發(fā)設(shè)計(jì)模式之——單例模式

http://blog.csdn.net/beyond0525/article/details/22794221

單例模式是設(shè)計(jì)模式中最常見(jiàn)也最簡(jiǎn)單的一種設(shè)計(jì)模式,保證了在程序中只有一個(gè)實(shí)例存在并且能全局的訪問(wèn)到。比如在Android實(shí)際APP 開(kāi)發(fā)中用到的 賬號(hào)信息對(duì)象管理,數(shù)據(jù)庫(kù)對(duì)象(SQLiteOpenHelper)等都會(huì)用到單例模式。下面針對(duì)一些例子分析一下我們?cè)陂_(kāi)發(fā)過(guò)程中應(yīng)用單例模式需要注意的點(diǎn)。

一、作用

單例模式(Singleton):保證一個(gè)類(lèi)僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)

二、適用場(chǎng)景

1. 應(yīng)用中某個(gè)實(shí)例對(duì)象需要頻繁的被訪問(wèn)。

2. 應(yīng)用中每次啟動(dòng)只會(huì)存在一個(gè)實(shí)例。如賬號(hào)系統(tǒng),數(shù)據(jù)庫(kù)系統(tǒng)。

三、常用的使用方式

(1)懶漢式

這是在開(kāi)發(fā)中很容易就能寫(xiě)出來(lái)的一種方式,如下

[java]view plaincopy

publicclassSingleton?{

/*?持有私有靜態(tài)實(shí)例,防止被引用,此處賦值為null,目的是實(shí)現(xiàn)延遲加載?*/

privatestaticSingleton?instance?=null;

/*?私有構(gòu)造方法,防止被實(shí)例化?*/

privateSingleton()?{

}

/*?1:懶漢式,靜態(tài)工程方法,創(chuàng)建實(shí)例?*/

publicstaticSingleton?getInstance()?{

if(instance?==null)?{

instance?=newSingleton();

}

returninstance;

}

}

調(diào)用:

[java]view plaincopy

Singleton.getInstance().method();

優(yōu)點(diǎn):延遲加載(需要的時(shí)候才去加載)

缺點(diǎn): 線程不安全,在多線程中很容易出現(xiàn)不同步的情況,如在數(shù)據(jù)庫(kù)對(duì)象進(jìn)行的頻繁讀寫(xiě)操作時(shí)。

(2)加同步鎖

既然線程不安全,那就加上同步鎖,一種加法如下:

[java]view plaincopy

/*2.懶漢式變種,解決線程安全問(wèn)題**/

publicstaticsynchronizedSingleton?getInstance()?{

if(instance?==null)?{

instance?=newSingleton();

}

returninstance;

}

更一般的寫(xiě)法是這樣

[java]view plaincopy

/*加上synchronized,但是每次調(diào)用實(shí)例時(shí)都會(huì)加載**/

publicstaticSingleton?getInstance()?{

synchronized(Singleton.class)?{

if(instance?==null)?{

instance?=newSingleton();

}

}

returninstance;

}

調(diào)用:

[java]view plaincopy

Singleton.getInstance().method();

優(yōu)點(diǎn):解決了線程不安全的問(wèn)題。

缺點(diǎn):效率有點(diǎn)低,每次調(diào)用實(shí)例都要判斷同步鎖

補(bǔ)充:android源碼中使用的該單例方法有:InputMethodManager,AccessibilityManager等都是使用這種單例模式

(3)雙重檢驗(yàn)鎖

要優(yōu)化(2)中因?yàn)槊看握{(diào)用實(shí)例都要判斷同步鎖的問(wèn)題,很多人都使用下面的一種雙重判斷校驗(yàn)的辦法

[java]view plaincopy

/*3.雙重鎖定:只在第一次初始化的時(shí)候加上同步鎖*/

publicstaticSingleton?getInstance()?{

if(instance?==null)?{

synchronized(Singleton.class)?{

if(instance?==null)?{

instance?=newSingleton();

}

}

}

returninstance;

}

這種方法貌似很完美的解決了上述效率的問(wèn)題,它或許在并發(fā)量不多,安全性不太高的情況能完美運(yùn)行,但是,這種方法也有不幸的地方。問(wèn)題就是出現(xiàn)在這句

[java]view plaincopy

instance?=newSingleton();

在JVM編譯的過(guò)程中會(huì)出現(xiàn)指令重排的優(yōu)化過(guò)程,這就會(huì)導(dǎo)致當(dāng) instance實(shí)際上還沒(méi)初始化,就可能被分配了內(nèi)存空間,也就是說(shuō)會(huì)出現(xiàn) instance !=null 但是又沒(méi)初始化的情況,這樣就會(huì)導(dǎo)致返回的?instance 不完整(可以參考:http://www.360doc.com/content/11/0810/12/1542811_139352888.shtml)。

調(diào)用:

[java]view plaincopy

Singleton.getInstance().method();

優(yōu)點(diǎn):在并發(fā)量不多,安全性不高的情況下或許能很完美運(yùn)行單例模式

缺點(diǎn):不同平臺(tái)編譯過(guò)程中可能會(huì)存在嚴(yán)重安全隱患。

補(bǔ)充:在android圖像開(kāi)源項(xiàng)目Android-Universal-Image-Loaderhttps://github.com/nostra13/Android-Universal-Image-Loader中使用的是這種方式

(4)內(nèi)部類(lèi)的實(shí)現(xiàn)

內(nèi)部類(lèi)是一種好的實(shí)現(xiàn)方式,可以推薦使用一下:

[java]view plaincopy

publicclassSingletonInner?{

/**

*?內(nèi)部類(lèi)實(shí)現(xiàn)單例模式

*?延遲加載,減少內(nèi)存開(kāi)銷(xiāo)

*

*?@author?xuzhaohu

*

*/

privatestaticclassSingletonHolder?{

privatestaticSingletonInner?instance?=newSingletonInner();

}

/**

*?私有的構(gòu)造函數(shù)

*/

privateSingletonInner()?{

}

publicstaticSingletonInner?getInstance()?{

returnSingletonHolder.instance;

}

protectedvoidmethod()?{

System.out.println("SingletonInner");

}

}

調(diào)用:

[java]view plaincopy

SingletonInner.getInstance().method();

優(yōu)點(diǎn):延遲加載,線程安全(java中class加載時(shí)互斥的),也減少了內(nèi)存消耗

(5)枚舉的方法

這是網(wǎng)上很多人推薦的一種做法,但是貌似使用的不廣泛,大家可以試試,

[java]view plaincopy

/**

*?@function:單例模式枚舉實(shí)現(xiàn)

*?@author?xuzhaohu

*

*/

publicenumSingletonEnum?{

/**

*?1.從Java1.5開(kāi)始支持;

*?2.無(wú)償提供序列化機(jī)制;

*?3.絕對(duì)防止多次實(shí)例化,即使在面對(duì)復(fù)雜的序列化或者反射攻擊的時(shí)候;

*/

instance;

privateString?others;

SingletonEnum()?{

}

publicvoidmethod()?{

System.out.println("SingletonEnum");

}

publicString?getOthers()?{

returnothers;

}

publicvoidsetOthers(String?others)?{

this.others?=?others;

}

}

調(diào)用:

[java]view plaincopy

SingletonEnum.instance.method();

優(yōu)缺點(diǎn):如代碼中注釋。

上面主要講了單例模式5種創(chuàng)建方法,大家可以根據(jù)其優(yōu)缺點(diǎn)進(jìn)行個(gè)人實(shí)際項(xiàng)目中的使用。講的屬于拋磚引玉,大家多提意見(jiàn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容