设计模式学习
设计模式是软件开发人员在软件开发过程中,对面临的一般问题的解决方案。这些方案是众多软件开发人员经过长时间的试验和错误总结出来的。
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 (单例模式)