單例模式

今天中午看到一個面試題,是這樣的,“怎樣設計一個類,使其只能有一個實例”,知道設計模式的程序員可能很快就能解決這個問題,就是Singleton模式。這裏我說說Singleton模式吧!

   單實例設可能是使用最廣泛的設計模式。其思想意圖是保證一個類只有一個實例,並且提供類對象的全程訪問。單實例對象應用的範圍很廣:如GUI應用必須是單鼠標,MODEM的聯接需要一條且只需要一條電話線,操作系統只能有一個窗口管理器,一臺PC連一個鍵盤。本文將討論如何用C++實現單實例模式,並解釋如何優化單線程應用的設計。

設計方案

    使用全程對象能夠保證方便地訪問實例,但是不能保證只聲明一個對象-也就是說除了一個全程實例外,仍然能創建相同類的本地實例。單實例模式通過類本身來管理其唯一實例,這種特性提供了問題的解決辦法。唯一的實例是類的一個普通對象,但設計這個類時,讓它只能創建一個實例並提供對此實例的全程訪問。唯一實例類Singleton在靜態成員函數中隱藏創建實例的操作。習慣上把這個成員函數叫做Instance(),它的返回值是唯一實例的指針。Singleton的定義如下:

class Singleton
{
public:
static Singleton* Instance();
protected:
Singleton();
Singleton(const Singleton&);
Singleton& operator= (const Singleton&);
private:
static Singleton* pinstance;
};

   你還可以創建諸如Mouse,FileManager,Scheduler等爲名字的類並聲明相應的成員。爲了保證用戶不能創建類的本地實例,Singleton的構造器是賦值操作符,構造函數的副本被聲明爲protected。類中還聲明瞭一個私有的靜態實例指針。當第一次調用靜態函數Instance()時,它創建唯一實例,將實例地址賦值給pinstance,然後返回這個地址。在每次併發調用中,Instance()也將只返回這個地址。

下面是類的實現:

Singleton* Singleton::pinstance = 0;// 初始化指針
Singleton* Singleton::Instance ()
{
if (pinstance == 0) // 是第一次調用嗎?
{
pinstance = new Singleton; // 創建唯一實例
}
return pinstance; // 唯一實例的地址
}
Singleton::Singleton()
{
//... 實現必要的實例初始化
}

    用戶訪問唯一實例的方法只有Instance()成員函數。如果不通過這個函數,任何創建實例的嘗試都將失敗,因爲類的構造函數是被保護的。Instance()使用懶惰初始化,也就是說它返回的值是當這個函數被首次訪問時被創建的。這是一種防彈設計-所有Instance()之後的調用都返回相同實例的指針:

Singleton *p1 = Singleton::Instance();
Singleton *p2 = p1->Instance();
Singleton & ref = * Singleton::Instance();

   雖然本文的例子針對的是單實例,但對Instance()稍加修改,這個設計模板便可適用於可變多實例情況。如一個類允許最多五個實例。

優化Singleton類,使之適用於單線程應用

   Singleton使用操作符new爲唯一實例分配存儲空間。因爲new操作符是線程安全的,在多線程應用中你可以使用此設計模板。但是有一個缺陷:就是在應用程序終止之前必須手工用delete摧毀實例。否則,不僅導致內存溢出,還要造成不可預測的行爲,因爲Singleton的析構函數將根本不會被調用。而通過使用本地靜態實例代替動態實例,單線程應用可以很容易避免這個問題。以下是與上面的Instance()稍有不同的實現,這個實現專門用於單線程應用:

Singleton* Singleton::Instance ()
{
static Singleton inst;
return &inst;
}

   本地靜態對象實例inst是第一次調用Instance()時被構造,一直保持活動狀態直到應用程序終止。指針pinstance變得多餘並可以從類定義中刪除掉。與動態分配對象不同,靜態對象當應用程序終止時被自動銷燬掉,所以就不必再手動銷燬實例了。

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/pingnanlee/archive/2009/04/20/4094313.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章