什么是Singleton模式?
Sigleton模式的设计意图是:保证一个类只有一个对象实例,并提供一个访问对象实例的全局访问点。
如果我们想实现一个全局范围可见的对象以替代麻烦缠身的全局变量,那么最好的做法就是将数据封装在一个特殊的类中。这个严格管理数据的创建过程以保证数据的唯一性,同时不允许程序员随意创建该类的对象实例。虽然不能通过类的构造函数获得对象实例,但可以通过该类提供的静态成员函数得到该类唯一的对象实例的指针或引用。
Singleton模式和全局变量有什么区别:
全局变量的问题:
(1)变量名冲突:必须小心维护变量名规则,所有工程师在开发代码时,每遇到一个全局变量,都必须仔细分辨该变量究竟属于哪个模块、哪个程序。
(2)耦合度难题:全局变量实际上增加了函数与模块之间的耦合度。用通俗的话说,需要访问某个特定全局变量的多个函数被该变量牢牢地“粘结”在一起,成为拆不散的一团乱麻。
(3)单个实体问题:全局变量不能阻止程序员定义一个类的多个对象实例。如果没有其它技术手段帮助,保证一个类只有单个实例就全靠程序员的自觉。
(4)初始化顺序:全局变量不能保证相互之间遵循特定的初始化顺序,这完全由编译器决定。对于类的对象实例,构造函数被调用的顺序有时就显得非常重要。
(5)多线程访问:当多个并发的线程都需要访问某些全局变量时,我们必须使用各种同步机制,小心地保护这些全局变量,以免陷入并发冲突的泥潭。
singleton模式的优点:
1)跨平台:使用合适的中间件,可以把singleton模式扩展为跨多个JVM和多个计算机工作。
2)适用于任何类:只需把一个类的构造函数变成私有的,并且在其中增加相应的静态函数和变量,就可以把这个类变成singleton。
3)可以透过派生创建:给定一个类,可以创建它的一个singleton之类。
4)延迟求值:如果singleton从未使用过,那么就决不会创建它。
singleton模式的代价 :
1)摧毁方法未定义:没有好的方法去摧毁一个singleton,或者解除其职责。即使添加一个decommission方法把theInstance置为null,系统中的其他模块仍然持有对该singleton实例的应用。这样,随后对Instance方法的调用会创建另外一个实例,致使同时存在两个实例。这个问题在C++中尤为严重,应为实例可以被摧毁,可能会导致去提领一个已被摧毁的对象。
2)不能继承:从singleton类派生出来的类并不是singleton。如果要使其成为singleton,必须要增加所需的静态函数和变量。
3)效率问题:每次调用Instance方法都会执行if语句。就大多数调用而言,if语句是多余的。
4)不透明性:singleton的使用者知道它们正在使用一个singleton,因为它们必须要调用Instance方法。
Singleton模式示例代码:
class Singleton
{
}
运用singleton模式:
多个应用程序都需要打印log信息,比如向同一个控制台或者同一个文件输出。此时是需要用到单一模式的,在多个进程或线程中,只能生成一个类的对象实例。
利用static关键字创建单一对象的数据结构 可以用在很多地方!在配合模板与类继承机制,可以达到一个管理器的作用!
基本代码:
class Singleton
{
public:
static Singleton* getSingleton();
private:
static Singleton* mInstance;
Singleton() { };
~Singleton() { if(mInstance ) {delete mInstance ; mInstance = 0; } } ;
}
Singleton* Singleton::mInstance = 0;
Singleton* Singleton::getSingleton()
if( ! mInstance )
mInstance = new Singleton();
return mInstance ;
在外部调用的时候不用考虑这个对象的内存管理!把构造放在私有空间,保证只有一个对象可以分配内存,外面调用的时候直接使用接口 Singleton::getSingleton();
但是这个函数局限性很大!不能扩展!
结合模板后可以更好的利用这种设计模式,代码如下:
template<typename T>
class Singleton
{
public:
Singleton(){ msInstance = static_cast<T*>(this);};
~Singleton(){} ;
static T* getSingletonPtr(void)
{
if(!msInstance)
return 0;
else
return msInstance;
};
static T& getSingleton(void)
{
if(!msInstance)
return 0;
else
return *msInstance;
};
protected:
private:
static T* msInstance;
};
只要有上面有这样一个模板类,以后的一些管理类就可以继承这个类
class Manager :public Singleton<Manager>
......
完成声明后还需要初始化一下 模板的静态成员
template<> Manager* Singleton<Manager>::msInstance = 0;
在使用 Manager mgr = Manager::getSingleton();前需要先外部分配内存
也就是程序初始化的时候声明一个Manager* Mgr = new Manager();
以后不管在哪个类里面只需要包含一下Manager.h就可以使用静态函数获得Manager的对象内存来完成管理