说在前面的话
今天开始打算把学过的设计模式总结一遍加深一下印象。也想把自己的心得分享给大家,如果有理解错误的地方希望大家能告诉我。初学设计模式的同学也可以看一下当作入门。
单例模式
其实我最早接触设计模式的时候第一个学的是简单工厂,简单工厂确实很简单,但是实话说我当初并没有学会。废话有点多,单例模式可以说是最常用的设计模式之一了。也是我在实际开发过程中经常要用到的一种模式。
简述
单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”
顾名思义,要的就是程序中有且只有一个此单例类的实例存在,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
应用场景
一般需要全局获取到的类我都会写成单例模式,这些类的成员一般保存了一些公共的数据或者有一些公共的方法用来调用。例如,XXManeger 类,这种类可能在代码中的任何地方用到,并且我们会把一些重要的数据保存在这类的成员里。然后我们提供一个GetInstance的方法,用来获取到这个唯一实例。当然这个这唯一实例的生命周期应该是进程级的,所以要定义成static。
实现方式
实现方式1.1:懒汉式
class Demo
{
public:
static Demo* GetInstance()
{
static Demo* p_demo = NULL;
if (p_demo == NULL)
{
p_demo = new Demo();
}
return p_demo;
}
private:
Demo();//将构造函数设置成私有,防止在其他地方构造此类。
};
实现方式1.2:饿汉式,由于静态变量初始化顺序不确定的原因,如果多个单例互相引用可能会出问题
//2 饿汉式
class Demo
{
public:
static Demo* GetInstance()
{
if (p_demo == NULL)
{
return NULL;
}
else
return p_demo;
}
private:
static Demo* p_demo;
Demo();//将构造函数设置成私有,防止在其他地方构造此类。
};
Demo* Demo::p_demo = new Demo;//在外部初始化类成员
实现方式2.1:懒汉式
class Demo
{
public:
static Demo GetInstance()
{
static Demo m_demo;
return m_demo;
}
private:
Demo();
};
实现方式2.2:饿汉式
class Demo
{
public:
static Demo GetInstance()
{
return m_demo;
}
private:
static Demo m_demo;
Demo();
};
这两种方法都有人用,第一种方法,谁new的谁delete,我们可以控制此类的分配和释放。第二种方法,是由程序来控制的。两种方法很类似,需要根据实际情况来选择,如果需要在程序运行过程中释放掉此单例类的话(比如运行过程中临时存在的类),那就用第一种,否则就用第二种(需要生命周期为进程级的类),因为第二种无法用delete释放,编译器会报错,可以避免错误的操作造成的bug。
一些零散的知识
懒汉模式:在GetIstance调用的时候创建。在需要的时候初始化,如果单例类占用内存非常多有很多的消耗,我们可以推迟实例,但是要注意多线程的时候初始化情况。
饿汉模式:静态初始化在类被加载的时候就创建。
静态初始化无法确定初始化的顺序,如果多个单例相互引用有可能出现问题,但是在多线程里可以避免懒汉模式初始化带来的问题。
单例模式的线程安全:
如果是多线程下使用单例模式,要注意在instance的时候增加线程锁。
双层锁:
if (p_Idemo == NULL)
{
//lock
lock();
if (p_Idemo == NULL)
{
p_Idemo = new Idemo;
}
//unlock
unlock();
}
}