Singleton模式: (单例模式)整个类只能生成一个对象
单例模式的三种经典设计方案:
1.延时加载,也称为懒汉模式,需要时才会创建对象;
2.贪婪加载,也称为饿汉模式,在程序执行前就已经创建好对象;
3.双重锁模式,延时加载升级版,加锁线程安全,需要时创建对象;
单例模式特点:
1.屏蔽生成对象的接口 ;
2.类中提供接口 来生成唯一对象 ;
(1.不能以类类型的方式返回
(2.接口是静态函数
一、延时加载
适用于单线程编程
class SingleTon
{
public:
static SingleTon* getInstance()
{
if (psing == NULL)
{
psing = new SingleTon();
}
}
return psing;
}
private:
SingleTon(){
}
SingleTon(const SingleTon&);
static SingleTon* psing;
};
SingleTon* SingleTon::psing = NULL;
测试样例:
SingleTon* psing1 = SingleTon::getInstance();
SingleTon* psing2 = SingleTon::getInstance();
SingleTon* psing3 = SingleTon::getInstance();
SingleTon* psing4 = SingleTon::getInstance();
调试结果:
bug:
延时加载只有在instance等于NULL时才创建,如果处于多线程环境,当未创建对象时另一线程也执行到相同阶段,程序就会出现问题。所以,我们可以给 程序加锁;
class SingleTon
{
public:
static SingleTon* getInstance()
{
lock();
if (psing == NULL)
{
psing = new SingleTon();
}
unlock();
}
return psing;
}
private:
SingleTon(){
}
SingleTon(const SingleTon&);
static SingleTon* psing;
};
SingleTon* SingleTon::psing = NULL;
可以看见,上述程序给if(psing == NULL) 的两边进行了lock()和unlock()操作
为什么要有加锁解锁操作?
多线程访问共享资源时,为防止产生脏数据和错误而采取的方式。多线程访问同一个数据库时,数据库是共享资源,所以对库操作要加锁。程序也是这个道理。
举例:1个厕所不能提供多人用,进入厕所加锁,使用完解锁。
上述程序当对象创建出来之后,还是会反复执行加锁解锁,占用 内存,降低效率。
所以 ,基于上边的程序,提出了双重锁机制
二、双重锁机制
所谓双重锁,就是在加锁之前判断对象是否已经创建成功,如果ture,就不执行加锁解锁操作。反之,执行此操作;
class SingleTon
{
public:
static SingleTon* getInstance()
{
if (psing == NULL)//没有命中 对象已经生成
{
lock();
if (psing == NULL)
{
psing = new SingleTon();
}
unlock();
}
return psing;
}
private:
SingleTon(){
}
SingleTon(const SingleTon&);
static SingleTon* psing;
};
SingleTon* SingleTon::psing = NULL;
三、贪婪加载
所谓贪婪加载,就是提前创建对象,利用静态全局变量,直接构建实例,并将静态指针指向同一内存块;
class SingleTon
{
public:
static SingleTon* getInstance()
{
return psing;
}
private:
SingleTon(){
}
SingleTon(const SingleTon&);
static SingleTon* psing;
};
SingleTon* SingleTon::psing = new SingleTon();
经过调试可以看见无论如何调用psing方法,都只有一个实例产生,这就实现了C++中的单例模式。