这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。使用单例模式可以保证一个类只生成一个对象实例,即在整个程序的生命周期内,该类的实例对象只存在一个。
单例模式特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
单例模式的实现可以分为饿汉式和懒汉式两种(LazySingletonPattern、HungrySingletonPattern)。
懒汉式的单例实现在多线程情况下容易出现异常,解决方法是利用线程锁进行线程同步。
懒汉式UML类图:
懒汉式:
#include <iostream>
using namespace std;
class Singelton
{
private:
Singelton() {}//构造函数私有,保证无法在类外new对象
static Singelton * m_singel;//静态成员
public:
static Singelton * getInstance()//静态成员方法才能使用静态成员变量
{
if (NULL == m_singel)
{
m_singel = new Singelton();
}
return m_singel;
}
};
Singelton * Singelton::m_singel = NULL;//静态成员变量的初始化需要放在类外
int main() {
Singelton * p1 = Singelton::getInstance();
Singelton * p2 = Singelton::getInstance();
if(p1==p2)
{
cout<<"singelton"<<endl;
}
return 0;
}
静态成员变量必须在类外初始化:
因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的,类外定义和初始化是保证static成员变量只被定义一次的好方法。
但是,懒汉式是线程不安全的,考虑两个线程同时首次调用instance方法且同时检测到p是NULL值,则两个线程会同时构造一个实例给p,这是严重的错误!
懒汉式单例模式,为了保证线程安全,需要加锁,lock
加锁方式一:双重加锁
if(m_instance== NULL)//先判断实例是否存在,不存在再加锁,避免多次加锁与解锁操作
{
Lock(); //上锁
if(m_singel== NULL) //加锁过程,其他线程可能已经new对象,所以需要重新判断,如果还未实例化,即可实例话,反之提供实例的引用
m_singel = new Singleton();
Unlock(); //解锁
}