设计模式读书笔记1-单例模式
单例模式属于创建型模式的一种,创建型模式是一类最常用的设计模式,在软件开发中应用非常广泛。创建型模式将对象的创建和使用分离,在使用对象时无需关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修改和扩展。每一个创建型模式都在视图回答3个问题:3W -> 创建什么(What)、由谁创建(Who)和何时创建(When)。
本篇是创建型模式的第一篇,也是最简单的一个设计模式,虽然简单,但是其使用频率确是很高的。
单例模式(Singleton) 学习难度:★☆☆☆☆ 使用频率:★★★★☆
1 单例模式的动机

相信大家都使用过Windows任务管理器,我们可以做一个尝试:在Windows任务栏的右键菜单上多次点击“启动任务管理器”,看能否打开多个任务管理器窗口。正常情况下,无论我们启动多少次,Windows系统始终只能弹出一个任务管理器窗口。也就是说,在一个Windows系统中,任务管理器存在唯一性。
在实际开发中,我们经常也会遇到类似的情况,为了节约系统资源,有时候需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,可以通过创建单例模式来实现,这也就是单例模式的动机所在。
2 单例模式的概述
2.1 单例模式定义
单例模式(Singleton Pattern)是一个比较简单的模式,其定义如下:
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建模式。
单例模式有3个要点:
- 某个类只能有一个实例
- 它必须自行创建这个实例
- 它必须自行向整个系统提供这个实例
2.2 单例模式结构图

从上图中可以看出,单例模式结构图中只包含了一个单例的角色。
Singleton(单例):
- 在单例类的内部实现只生成一个实例,同时它提供一个静态的GetInstance()方法,让客户可以访问它的唯一实例;
- 为了防止在外部对单例类实例化,它的构造函数被设为private;
- 在单例类的内部定义了一个Singleton类型的静态对象,作为提供外部共享的唯一实例。
3 软件设计
3.1 软件需求
中国的历史上很少出现两个皇帝并存的时期,是有,但不多,那我们就认为皇帝是个单例模式,在这个场景中,有皇帝,有大臣,大臣是天天要上朝参见皇帝的,今天参拜的皇帝应该和昨天、前天的一样(过渡期的不考虑,别找茬哦),大臣磕完头,抬头一看,嗨,还是昨天那个皇帝,单例模式,绝对的单例模式,先看类图:

static Emperor *singleton;
Emperor* CreateInstance(void)
{
Emperor* emperor = (Emperor *)malloc(sizeof(Emperor));
if(!emperor)
{
return NULL;
}
memset(emperor, 0, sizeof(emperor));
strcpy(emperor->name, "huangdi");
emperor->age = 24;
return emperor;
}
Emperor* GetInstance(void)
{
return singleton;
}
现在我们在客户端代码中添加一些测试代码,看看结果:
int main(void)
{
int i = 0;
Emperor *ps2;
singleton = CreateInstance();
for(i = 0; i < 3; i++)
{
ps2 = GetInstance();
printf("name: %s,age: %d\n",ps2->name, ps2->age);
}
return 0;
}
3.2 懒汉模式和饿汉模式
测试例子中采用的是饿汉模式,懒汉模式又称为延迟加载,也就是首次使用的时候初始化
static Emperor *singleton;
Emperor* GetInstance(void)
{
if(!singleton)
{
singleton = (Emperor *)malloc(sizeof(Emperor));
if(!singleton)
{
return NULL;
}
memset(singleton, 0, sizeof(singleton));
strcpy(singleton->name, "huangdi");
singleton->age = 24;
}
return singleton;
}
4 单例模式的应用
单例模式目标明确,结构简单,在软件开发中使用频率相当高。
4.1 单例模式优点
- 由于单例模式在内存中,只有一个实例,减小了内存开支,特别是一个对象需要频繁的创建、销毁,创建和销毁时性能无法优化,单例模式的优势就足够的明显
- 由于单例模式只生成一个实例,减小了系统的性能开销,当一个对象的产生较多的资源时,如读取配置、产生其他依懒对象时
- 单例模式可以避免对资源的多重占用,例如写一个文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作
- 单例模式可以在系统设置全局的访问点,优化和共享资源访问
4.2 单例模式缺点
- 单例模式没有接口,扩展很困难
- 单例模式对测试不利,在并行开发环境中,如果单例模式没有完成,是不能进行测试
- 单例模式与单一职责原则有冲突
4.3 单例模式的使用场景
在一个系统中,要求有且仅有对象,如果出现多个对象就会出现不良反应,可以采用单例模式,具体场景如下:
- 要求生成唯一序列号的环境
- 在整个项目中需要一个共享访问点和共享访问数据
- 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源
- 需要定义大量的静态常量和静态方法的环境,可以采用单例模式,也可以直接声明为static
5 单例模式注意事项
在高并发的情况下,请注意单例模式的线程同步问题
6 参考资料
秦晓波, 《设计模式之禅》
刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

浙公网安备 33010602011771号