从零开始学设计模式——单例模式

设计模式学习

 设计模式是软件开发人员在软件开发过程中,对面临的一般问题的解决方案。这些方案是众多软件开发人员经过长时间的试验和错误总结出来的。
 

1 设计模式简介

 设计模式,一套被多数人反复使用、经过分类编目的代码设计经验总结。使用设计模式为重用代码,使代码被他人理解,进而保证代码的可靠性。设计模式使代码编程真正工程化,是软件工程的基石。

 设计模式主要是基于面向对象设计原则。
  ·对接口编程而不是对实现编程;
  ·优先使用对象组合而不是继承;
 

1.1 设计模式的六大原则

 1)开闭原则(Open Close):
  对扩展开放,对修改关闭。在程序需要拓展的时候,不能修改原有的代码,而是使用接口和抽象类,实现热插拔的效果;

 2)里氏代换原则(Liskov Substitution):
  父类出现的任何地方,子类一定可以出现。里氏代换原则对开闭原则的扩充,抽象化是实现开闭原则的关键,而父类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范;

 3)依赖倒转原则(Dependence Inversion):
  针对接口编程,而不是依赖于具体;

 4)接口隔离原则(Interface Segregation):
  使用多个隔离的接口,比使用单个接口要好,即降低类之间的耦合度。由此可见,设计模式是从大型软件架构出发,便于升级和维护的软件设计思想,强调降低依赖、耦合。

 5)迪米特法则(Demeter):
  一个实体应当尽量少地与其他实体发生相互作用,使得系统功能模块相对独立。

 6)合成复用原则(Composite Reuse):
  尽量使用合成/聚合的方式,而不是使用继承。
 

1.2 设计模式的分类

 设计模式共有25种,可分为三大类:创建型、结构型及行为型。
 

2 创建型设计模式

 创建型设计模式,提供一种在创建对象时,隐藏其创建逻辑的方式,不再直接实例化对象。根据具体场景,由程序来确定创建对象的方式,保证更好的性能,更好的架构优势。(即需要在自定义函数内初始化?)
 创建型设计模式主要包括:工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式五种;
 

2.1 单例模式

2.1.1 使用场景

 1)单例模式,节省公共资源。例如,一个班级只有一个班主任。
 2)单例模式,方便控制。例如,Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
 3)单例模式,主要解决一个全局使用的类,被频繁地创建与销毁。
 

2.1.2 解决思路

 判断该系统是否已经存在这个单例对象,如果存在,则返回;否则,创建该单例对象。
 

2.1.3 优点与缺点
1) 优点

 1.1)在内存中只存在一个实例,减少内存的开销,尤其是频繁地创建、销毁实例;
 1.2)避免对资源地多重占用,比如,写文件操作;

2) 缺点

 2.1)没有接口,不能继承,与单一职责原则冲突。
 

2.1.4 实现
2.1.4.1 类定义
1) SingleObject类

 1.1)成员变量:
  ·静态实例;

 1.2)成员方法:
  ·私有的构造函数;
  ·公有的静态方法,用于外界获取它的静态实例;
 

2) 示意图

单例模式类定义示意图
 

3) 实现

 3.1) 懒汉式,线程不安全。

  3.1.1) 描述
   最基本的实现方式,该实现最大的问题是不支持多线程,因为没有加锁,所以严格意义上,不属于单例模式,仅供理解。

  3.1.2) 代码

class Singleton{
private:
	static Singleton* m_pSingleton;
	
private:
	Singleton();
	Singleton(const Singleton&);				// 将拷贝构造函数作为私有函数,禁止外部拷贝;
	const Singleton& operator=(const Singleton&);	// 将赋值构造函数作为私有函数,禁止外部赋值;
	~Singleton();

public:
	static Singleton* getInstance(){
		if (nullptr == m_pSingleton){
			m_pSingleton = new Singleton();
		return instance;
		}
	}

	static void delInstance(){
		delete m_pSingleton;
	}
};	// Singleton类定义

 3.2) 懒汉式,线程安全

  3.2.1) 描述
   该方式具有很好的Lazy Loading,能够在多线程中很好的工作,但效率较低。必须进行加锁才能保障单例。

  3.2.2) 代码

class Singleton{
private:
	static Singlton* m_pSingleton;
	static std::mutex m_Mutex;
	
private:
	Singleton();
	Singleton(const Singleton&);
	const Singleton& operator=(const Singleton&);
	~Singleton();

public:
	static Singleton* getInstance(){
		if (nullptr == m_pSingleton){
			std::unique_lock<std::mutex> lock(m_Mutex);
			if (nullptr == m_pSingleton){
				m_pSingleton = new Singleton();
			}
		}
		return m_pSingleton;
	}
	
	static void delInstance(){
		if (nullptr == m_pSingleton){
			std::unique_lock<std::mutex> lock(m_Mutex);
			if (nullptr == m_pSingleton){
				delete m_pSingleton;
			}
		}
	}
};

 3.3) 饿汉式

  3.3.1) 描述
   该方法比较常用,但容易产生垃圾对象。
   ·优点是没有加锁,执行效率提高。
   ·缺点是类加载时就初始化,浪费内存。

  3.3.2) 代码

class Singleton{
private:
	static Singleton* m_pSingleton;
	
private:
	Singleton();
	Singleton(const Singleton &);
	const Singleton& operator=(const Singleton&);
	~Singleton();

public:
	static Singleton* getInstance(){
		return m_pSingleton;
	}

	static void delInstance(){
		delete m_pSingleton;
	}
};
// 与类定义放在同一文件中(.hpp文件,既有h又有cpp),在类加载的时候就已经初始化好了。
Singleton* Singleton::m_pSingleton = new Singleton();	

 

参考网址

[1] https://www.runoob.com/design-pattern/design-pattern-tutorial.html (设计模式概述)
[2] https://zhuanlan.zhihu.com/p/345535718 (设计模式的三大类)
[3] https://zhuanlan.zhihu.com/p/51854665 (单例模式)
[4] https://zhuanlan.zhihu.com/p/37469260 (单例模式)
[5] https://blog.csdn.net/lvyibin890/article/details/81943637 (单例模式)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值