一口气看完设计模式

题目有点夸张,本文主要是对各个设计模式的特点和区别进行介绍,主要是个人理解,欢迎大家一起讨论,并不会详细介绍各个设计模式的实现方式。详细的设计模式相关内容推荐两个链接

  • 图说设计模式
  • C++设计模式系列
设计模式总体上可以分为三大类:创建型、结构型和行为型模式,下面分别从这三个类型方向介绍各个模式的特点和区别(对应的每个模式后面有一个星级别来自图说设计模式)。
创建型模式 创建型模式的本质在于:对创建过程进行封装,使得对象的创建变成一个独立过程,便于后续对创建的细节的调整和创建对象的扩展
1、简单工厂(4)
设计一个工厂类,可以创建所有的对象。简单、直观,但扩展差,主要表现在添加新对象类型的创建时,需要改动已有的代码。
2、工厂方法(5)
改进简单工厂,核心是对工厂提供的方法进行接口抽象,不同产品的设计不同的工厂子类。这样使用上是统一的工厂提供的接口,但实现上可以通过添加子类实现添加新的产品。但可能存在的问题是一个产品对应一个工厂导致工厂类泛滥。
3、抽象工厂(5)
工厂方法改进,每个工厂都提供多个一致的创建接口,创建相关的产品,避免每个产品都对应一个工厂子类。
4、单例模式(4)
c++中对全局变量的封装,通常是private构造+static成员函数+返回指针,需主要多线程的初始化问题(加锁或者static局部变量)和GC问题(析构static 成员函数)
5、建造者模式(2)
对同一类型的多种复杂的类对象的构造流程进行封装,抽象成一个director类,不同的对象构造流程的各个阶段实现为builder_x类的成员函数,builder只负责各个阶段的实现,director负责将builder各个阶段进行组合,典型的设计和实现解耦。
6、原型模式(3)
主要实现clone()函数,拷贝自身。本质上是对象具有拷贝需求,但直接构造(可能参数较多)+设置状态可能比较麻烦,clone就是对这个过程的一个封装。
结构型模式 结构型模式的本质在于:描述类类、类对象之间的结合方式,实现上基本上都是尽量利用组合/关联关系替代继承关系。
7、适配器模式(4)
对接口转换的代码进行封装,从一个标准的接口A转换到另外一个标准的接口B。adapter类通常通过继承B_abstract接口,包含A_impl对象实现。
8、组合模式(4)
描述了一种存在局部-整体特性的层次的组合方式,适用于对一颗树的叶子节点的操作方式和对树的非叶子节点的操作方式有一致性的需求场景(后者会对以该节点为根的子树的每一个节点进行操作)。其实现上的重点在于分层+抽象对节点的一致操作接口,好处在于操作的一致性,单节点和节点集合的操作方式是一致的。
9、桥接模式(3)
桥接是利用组合连接多个维度的变化,避免继承处理多个维度变化导致类的泛滥,这句话可能比较难理解。如下图可能会比较好理解

一口气看完设计模式
文章图片
桥接模式
10、装饰模式(3)
对以组合的方法对核心功能进行扩展的一种方式,扩展的类在接口上表现为is-a的关系(继承),但在实现上表现为has-a关系。具体接口的实现上的关键在于在核心功能前后装饰作用,即功能扩展。与桥接的区别:桥接为的是解决单纯靠继承解决多个维度变化导致的类泛滥,装饰主要是为核心功能进行扩展,实现是比较类似。
11、外观模式(5)
对复杂的子系统执行流程进行封装,对外暴露更加友好的接口。其实就是在外部调用和内部实现之间加了一个简单层,使内部实现和外部调用解耦。相比于组合模式,要求更少(不需要层次结构,不需要一定的单点和集合的一致性接口)实现上更为简单。
12、享元模式(1)
实际上就是为了达到类对象的共享,使用工厂类管理共享的对象,存在则返回,不存在则分配,减少细粒度的类对象的数量。
13、代理模式(4)
实际对对象进行一层封装,导出相同的接口,其目的在于封装控制,在封装层做一些控制类的东西,典型例子是智能指针对指针的代理。与适配器的区别在于适配器是进行接口转换适配,于装饰模式的区别在于装饰模式在于功能扩展。
行为型模式 行为模式主要是根据具体的场景描述各个对象之间的相互关系和职责和通信方式。
14、解释器模式(1)
这个主要是树形结构的语法树实现,貌似jsonlogic的解析可以用到这种模式。
15、迭代器模式(5)这个居然是5 --!
这个主要是将迭代进行抽象,导出统一的接口,对应不同的需要迭代的对象(容器),将其导入迭代器后,迭代器内部利用容器提供的操作实现该容器的遍历迭代方式。
16、中介者模式(2)
抽象多个对象之间的通信部分的逻辑,多个对象只需要和中介对象进行通信即可,内部实现各个对象的消息封装转发等逻辑,避免将这部分比较恶性的逻辑分散到各个对象的实现中。
18、备忘录模式(2)
实际上就是一种类的存档和恢复机制,其实际处理的是需要抽象封装对象内部需要保存数据,并且对象提供该数据对象的设置和保存接口。
19、观察者模式(5)
描述的是一种实现订阅-通知的关系,被观察者实现注册机制,观察者实现回调处理函数,并进行注册,当被观察者发生事件状态时通过回调进行通知处理。
20、状态模式(3)
实际是对状态和处理方式进行封装,一个状态对应一个类,内部封装了对应的状态处理方式。通过一个上下文类对不同的状态直接调用其对应的处理函数即可。
21、策略模式(4)
感觉实现上和状态模式类似,对策略的处理方式进行抽象导出统一的接口,这样对一个上下文,导入不同的策略对象,即可以执行不同的策略。
22、职责链模式(3)
描述的是一种串行的执行逻辑,前面的执行到一定状态则执行下一个状态,否则其他逻辑,将这部分处理和承上启下的逻辑分散到各个对象的内部,避免在一个地方进行处理,导致处理的地方复杂臃肿。
23、命令模式(4)
这个没有用到,不太理解;感觉是对各个命令进行封装,导出一致的接口,同时抽象一个controller对命令对象进行封装。外部只需要调用controller就可以了,感觉上是对命令执行这个一步到位的操作进行了两层的封装,留出后续可以扩展的余地。
24、访问者模式(1)
访问者模式感觉是一个反向的思维,直观理解,一个访问者需要访问一个元素,则将该元素传递个该访问者即可;但当元素比较固定的时候,访问者类型比较多的时候,将导致违背另外一个常识,即变化多的量应该作为一个参数传到有限不同的方法中。访问者模式即这样一种情况,当元素比较固定,但访问的方式多种多样时,在元素上实现accepter(vistor){visortor->visit(this)}这样的结构,这样在外部调用的时候更加符合变化多的量作为参数进行传导的逻辑。
【一口气看完设计模式】25、模板方法模式(3)
感觉像是装饰模式以模板化的形式进行提供,不同的继承子类可以具体实现装饰的功能。具体实现的思想如下。
class base{ public: void run(){ pre(); ... post(); } virtual void pre() {} virtual void post() {} } class A: public base{ void pre(){...} void post(){...} } class B: public base{ void pre(){...} void post(){...} }

总结 最后说一点对设计模式的总体理解,总体感觉结构框架的设计就是将简单的东西复杂化,但是在其复杂化是为了后续的更好扩展,框架功能的合理划分,便于框架去处理异常复杂的情况。但是如何复杂化呢?最直接的就加层,在合理的地方加上一层,便于后续在这个地方进行其他处理,当然还有其他的情况,例如设计订阅-通知模式,订阅机制在后续在扩展其他订阅者是统一的,同时代码的修改也不影响其他订阅者等等,所有的这些复杂化的过程经验就是设计模式。总体原则:发现变化并封装、提供更加友好的接口、功能细致化划分、同类型功能逻辑封装抽象。

    推荐阅读