在实际开发中,我们往往需要一个类只能被实例化一次,如果有多个对象的话,就会导致混乱情况发生。
优点
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
缺点
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。。
今天我们就来实现以下三个单例模式
1.懒汉式
class test
{
public:
static test * gettest()
{
if (p == NULL)
p = new test();
return p;
}
private:
test() {};
static test*p;
};
我们将类的构造函数声明为私有的,这样就不能通过构造函数来创建类对象,定义一个静态的gettest()函数来创建获取类资源,而这个函数不需要创建类对象,只需要通过类名访问即可。只有在第一次创建类对象时,资源进行了分配,其余时候不进行分配。这样就实现了一个类只有一个实例的要求。
缺点:存在内存泄露。new出来的东西始终没有释放。
2.饿汉式
class test {
private:
static test* p;
test();
class test2 {
public:
~test2()
{
if (test::p)
{
delete test::p;
}
}
};
static test2 t;
public:
static test* gettest()
{
if (p == NULL)
{
p = new test();
return p;
}
}
};
这里采用一种内嵌定义的方式,定义一个test2类,专门只做一件事,就是用来释放new出来的资源,当程序运行结束时,系统会自动析构所有的全局变量。会自动调用test2的析构函数,把p的资源释放。
饿汉式的特点是一开始就加载了,如果说懒汉式是时间换空间,那么饿汉式就是用空间换时间。
class test
{
private:
test() {}
public:
test* gettest()
{
static test t;
return &t;
}
}
这是一种饿汉式的方法,当类被创建好了之后,就已经存在一个静态的对象供系统使用,以后不会再改变。但是这也会存在一个问题,当我们使用下面的方法来调用的好时
test t1=test::gettest();就会出现一个类拷贝的问题,这就违背了单例模式的要求,因为编译器会给我们合成一个默认的构造函数,来支持类的拷贝。最后我们没办法,只能将类的拷贝构造函数和赋值运算符的重载声明为私有。于是有了下面这种代码。
class test
{
private:
test() {}
test(const test&t);
test& operator=(const test&t);
public:
test* gettest()
{
static test t;
return &t;
}
}