設計模式思想是可重用,我們在編程的過程中,或多或少都會接觸到設計模式,只是,有時,我們相交卻未相識罷了,那麼我們今天來講解單例模式,並且附之一個C++的編程技巧。
我們知道單例模式在實際開發過程中是很有用的,單例模式的特征我們可能都知道:
1、一個類只有一個實例
2、提供一個全局訪問點
3、禁止拷貝
我們來逐個分析:
1、如果要實現只有一個實例,我們需要做的事情:
a、將構造函數聲明為私有
2、提供一個全局訪問點
a、類中創建靜態成員函數
3、禁止拷貝
a、拷貝構造函數聲明為私有,並且不提供實現
b、將賦值運算符聲明為私有
我們在書寫單例類的時候如何測試呢?兩個方法:
1、實例化多個對象,看調用了幾次構造函數,如果只調用一次,說明只創建一個實例
2、單步跟蹤,查看對象的地址,是否一樣,一樣則為一個對象
------------我是分割線-------------
在學習C++的過程中,我們很早就接觸到了構造函數和析構函數,這兩個函數都是系統自動調用的,縱使我們不聲明構造函數和析構函數,系統也會替我們生成。
那麼在C++編程就有確定性析構,也就是是說,無論怎麼樣,只要創建了對象,系統就會調用析構函數,那麼如果我們在類中嵌套一個類,並且在外面類中聲明一個嵌套類對象,那麼,嵌套類對象的析構函數是一定調用的,我們可不可以在嵌套類的析構函數裡面做點東西呢?
我們的方法是:
在單例類Singleton中定義為Garbo的私有內嵌類,以防該類被在其他地方濫用。
程序運行結束時,系統會調用Singleton的靜態成員Garbo的析構函數,該析構函數會***單例的唯一實例
使用這種方法釋放單例對象的特征:
1、在單例類內部定義專有的嵌套類;
2、在單例類內定義私有的專門用於釋放的靜態成員;
3、利用程序在結束時析構全局變量的特性,選擇最終的釋放時機;
4、使用單例的代碼不需要任何操作,不必關心對象的釋放。
C++ Primer Plus 第6版 中文版 清晰有書簽PDF+源代碼 http://www.linuxidc.com/Linux/2014-05/101227.htm
讀C++ Primer 之構造函數陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm
讀C++ Primer 之智能指針 http://www.linuxidc.com/Linux/2011-08/40177.htm
讀C++ Primer 之句柄類 http://www.linuxidc.com/Linux/2011-08/40175.htm
C++11 獲取系統時間庫函數 time since epoch http://www.linuxidc.com/Linux/2014-03/97446.htm
C++11中正則表達式測試 http://www.linuxidc.com/Linux/2012-08/69086.htm
代碼如下:
------------我是分割線-------------
# include <iostream>
using namespace std;
//當static Garbo garbo_ 對象的生命周期結束時,會調用嵌套類Garbo的析構
//函數,同時也instance_的銷毀
//利用了對象確定性析構的原則
//施加約束,只有一個實例,只需要將構造函數聲明為私有的
//需要一個全局的訪問點,
class Singleton
{
public:
static Singleton* GetInstance()
{
if(NULL == instance_)
{
instance_ = new Singleton;
}
return instance_;
}
~Singleton()
{
cout << "~Singleton ..." << endl;
}
/*這種方法也可以釋放資源,是笨方法
static void Free()
{
if(NULL != instance_ )
{
delete instance_;
}
}
*/
//嵌套類
class Garbo
{
public:
~Garbo()
{
if(Singleton::instance_ != NULL)
{
delete instance_;
}
}
};
private:
//拷貝構造函數聲明為私有,就可以禁止拷貝,並且不提供實現
Singleton(const Singleton& other);
//也要禁止賦值,將賦值運算符聲明為私有
Singleton& operator=(const Singleton& other);
Singleton()
{
cout << "Singleton ..." << endl;
}
//僅僅是聲明,如果定義,需要放在類外面
static Singleton* instance_;
//創建garbo對象,是聲明
static Garbo garbo_;
//利用了對象確定性析構的原則
};
//因為Garbo是嵌套類,所以前面要加SIngleton
Singleton::Garbo Singleton::garbo_; //前面的static就不需要了
Singleton* Singleton::instance_;
int main(void)
{
//不管GetInstance調用多少次,都返回是同一個實例
Singleton* s = Singleton::GetInstance();
Singleton* s1 = Singleton::GetInstance();
//Singleton s3(*s); error 禁止拷貝
//Singleton s3 = *s; error 禁止賦值
//構造幾個實例,就調用幾個構造函數,所以只調用一次構造函數
//Singleton::Free(); 對資源進行釋放,此為笨方法
return 0;
}
------------我是分割線-------------
PS:
1、上述方法不是線程安全的
2、還可以利用智能指針auto_ptr實現,我們後期再論
3、除了嵌套類,上面還給出了笨方法,大家挖掘
------------我是分割線-------------