设计模式读书笔记1-单例模式

单例模式属于创建型模式的一种,创建型模式是一类最常用的设计模式,在软件开发中应用非常广泛。创建型模式将对象的创建和使用分离,在使用对象时无需关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修改和扩展。每一个创建型模式都在视图回答3个问题:3W -> 创建什么(What)、由谁创建(Who)和何时创建(When)。
 

  本篇是创建型模式的第一篇,也是最简单的一个设计模式,虽然简单,但是其使用频率确是很高的。

单例模式(Singleton) 	学习难度:★☆☆☆☆ 	使用频率:★★★★☆

1 单例模式的动机

avatar

  相信大家都使用过Windows任务管理器,我们可以做一个尝试:在Windows任务栏的右键菜单上多次点击“启动任务管理器”,看能否打开多个任务管理器窗口。正常情况下,无论我们启动多少次,Windows系统始终只能弹出一个任务管理器窗口。也就是说,在一个Windows系统中,任务管理器存在唯一性。

  在实际开发中,我们经常也会遇到类似的情况,为了节约系统资源,有时候需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,可以通过创建单例模式来实现,这也就是单例模式的动机所在。

2 单例模式的概述

2.1 单例模式定义

单例模式(Singleton Pattern)是一个比较简单的模式,其定义如下:
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建模式。
单例模式有3个要点:

  1. 某个类只能有一个实例
  2. 它必须自行创建这个实例
  3. 它必须自行向整个系统提供这个实例

2.2 单例模式结构图

从上图中可以看出,单例模式结构图中只包含了一个单例的角色。

  Singleton(单例):

  1. 在单例类的内部实现只生成一个实例,同时它提供一个静态的GetInstance()方法,让客户可以访问它的唯一实例;
  2. 为了防止在外部对单例类实例化,它的构造函数被设为private;
  3. 在单例类的内部定义了一个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 单例模式优点

  1. 由于单例模式在内存中,只有一个实例,减小了内存开支,特别是一个对象需要频繁的创建、销毁,创建和销毁时性能无法优化,单例模式的优势就足够的明显
  2. 由于单例模式只生成一个实例,减小了系统的性能开销,当一个对象的产生较多的资源时,如读取配置、产生其他依懒对象时
  3. 单例模式可以避免对资源的多重占用,例如写一个文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作
  4. 单例模式可以在系统设置全局的访问点,优化和共享资源访问

4.2 单例模式缺点

  1. 单例模式没有接口,扩展很困难
  2. 单例模式对测试不利,在并行开发环境中,如果单例模式没有完成,是不能进行测试
  3. 单例模式与单一职责原则有冲突

4.3 单例模式的使用场景

在一个系统中,要求有且仅有对象,如果出现多个对象就会出现不良反应,可以采用单例模式,具体场景如下:

  1. 要求生成唯一序列号的环境
  2. 在整个项目中需要一个共享访问点和共享访问数据
  3. 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源
  4. 需要定义大量的静态常量和静态方法的环境,可以采用单例模式,也可以直接声明为static

5 单例模式注意事项

在高并发的情况下,请注意单例模式的线程同步问题

6 参考资料

秦晓波, 《设计模式之禅》

刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

posted @ 2018-11-06 09:09  奇小葩  阅读(96)  评论(0)    收藏  举报