GOF的《设计模式》中这样描述:保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能阻止你实例化多个对象。一个最好的办法是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
也就是说,很多时候我们需要全局的对象,如一个工程中,数据库访问对象只有一个,这时,可以考虑使用单例模式。单例模式比全局对象好还包括:单例类可以继承,如下例。
单例模式的关键点在于:构造函数私有,静态的GetInstance。
另外,在C++中必须注意内存的释放。C++、Java、C#中还要注意多线程时的同步问题。
- #include <iostream.h>
- class CSingleton
- {
- public:
- static CSingleton * GetInstance()
- {
- if(NULL == m_pInstance)
- m_pInstance = new CSingleton();
- return m_pInstance;
- }
- static void Release() //必须,否则会导致内存泄露
- {
- if(NULL != m_pInstance)
- {
- delete m_pInstance;
- m_pInstance = NULL;
- }
- }
- private:
- CSingleton()
- {
- cout<<"CSingleton"<<endl;
- };
- static CSingleton * m_pInstance;
- };
- CSingleton* CSingleton::m_pInstance = NULL;
- class CSingleDraw:public CSingleton
- {
- public:
- static CSingleDraw* GetInstance()
- {
- if(NULL == m_pInstance)
- m_pInstance = new CSingleDraw();
- return (CSingleDraw*)m_pInstance;
- }
- protected:
- CSingleDraw()
- {
- cout<<"CSingleDraw"<<endl;
- }
- };
- int main()
- {
- CSingleDraw* s1 = CSingleDraw::GetInstance();
- CSingleDraw* s2 = CSingleDraw::GetInstance();
- s2->Release();
- return 0;
- }
——————————————————————————
这个方法实现singleton不太好,会有多线程同步问题。
比如说一开始Singleton::instance为空。然后有线程A和线程B同时访问Singleton::GetInstance()。
有意思的是当任务A执行if (NULL == instance)这句时,刚判断好instance确实为空想调用new,或者时间可以再放款到正在执行new操作,但是还没有返回;要命的是调度器由于某些原因一下子剥夺了线程A的执行又去执行线程B了。线程B顺利地创建了一个instance实例,然后在某一时刻被调度器剥夺,再次执行线程A。OK,此时线程A从刚才的混沌中继续执行它的new Singleton()的操作,这样线程A所创建出来的就是另一个实例了。此时Singleton宣告破灭。
因此,能够迎合多线程,乃至多处理的单件处理可以用以下方式:
class Singleton
{
private:
static Singleton instance;
Singleton(void)
{
}
public:
static Singleton& GetInstance()
{
return instance;
}
};
Singleton Singleton::instance;