标签:
1、至多有且仅有一个唯一的实例,不一定就一定要将构造函数的访问权限定为private,我们可以通过各种各样的方法来实现它的构造函数只能成功地执行一次。但是,将构造函数定为private直观省事。
private: Singleton(void);
2、既然我们将构造函数定为private,外部是无法构建它的实例。因此,我们就需要一个不需要它的实例也能够被访问的函数,这就是静态函数。能够被外部访问,毫无疑问它的访问权限应该是public(虽然能过通过一系列强制转换直接通过地址来调用函数,此处忽略不计)
public: static Singleton* getInstance(void);
3、我们只构造一次,因此需要用一个成员变量来记录它的地址。上面已经提到,我们使用静态函数来向外部提供访问接口,众所周知,在静态函数中只能使用静态变量。对于这个静态成员变量的访问权限没有严格的定义,但是,为了体现封装性,我们再次将其定位private。
private: static Singleton* _instance;
4、在此贴上整体单例类
class Singleton { public: ~Singleton(void); static Singleton* getInstance(void); private: Singleton(void); private: static Singleton* _instance; }; Singleton::Singleton(void) { std::cout<<"I am Singleton !\n"; } Singleton::~Singleton(void) { if (NULL != _instance) { delete _instance; _instance = NULL; } } Singleton* Singleton::getInstance(void) { if (NULL == _instance) { _instance = new Singleton(); if (NULL == _instance) { std::cout<<"Singleton instance new is failed !\n"; } } return _instance; }
5、经过上面3个步骤就能够完成粗糙的单例了,为什么是粗糙的呢?内存回收、多线程运用。
当一个项目越来越庞大,使用的单例越来越多,逻辑关系越来越复杂,什么时候销毁这些单例会使我们迷惑;上面的单例实现在多线程的环境下可能产生多个实例。
6、对于内存管理使用较为简单的是使用局部静态变量,静态变量只初始化一次,存储空间不在栈,在程序退出时将自动被销毁。
Singleton* Singleton::getInstance(void) { static Singleton instance; return &instance; }
还有一种方法是在单例类内写一个内部类并持有一个该内部类的静态成员,但是感觉上怪怪的。
7、对于多线程,一种是使用饱汉模式(在使用到单例实例前就创建好实例,上面的实现位饿汉模式,需要使用实例是才创建实例),下面是加锁
Singleton* Singleton::getInstance(void) { if (NULL == _instance) { lock(); if (NULL == _instance) { _instance = new Singleton(); if (NULL == _instance) { std::cout<<"new Singleton() failed !\n"; } } unlock(); } return _instance; }
为什么要在lock的都两边加上 if (NULL == _instance) 呢?如果只用一个判空,lock放在判空前,那么我们在每一次获取实例时都要执行lock,大大滴降低了效率;那么放在判空后面,那么将可能有多个线程在第一个实例创建出来前通过判空依次等待创建多个实例。
总结:
实例数量受限,可根据需求设定实例数量,节省内存等,这是它的好处。难于扩展,违背单一原则这是它的坏处。
具体的软件设计行为中,自然是具体情况具体分析,全局变量不就是简单的单例。
标签:
原文地址:http://www.cnblogs.com/haihuahuang/p/4433725.html