设计模式快速复习

设计模式快速复习

Design Pattern Explanation with C++ Implementation(By K_Eckel) 的阅读总结

创建型模式

Factory :提供一个专门用来创建对象的工厂类,而不是直接使用 new ;

  • 可以根据运行时的情况来判断究竟是实例化谁,代码可读性强
  • 只能用于一类类(例如有一个共同的基类),腰围不同的类提供一个对象创建的结构,需要用到 AbstractFactory

请添加图片描述

AbstractFactory:用于创建一组相关或者相互依赖的对象,基于 Factory 实现

请添加图片描述

Singleton :创建一个全局唯一的变量,即使在纯面向对象范式的编程当中,也可以不借助全局变量来实现单例。

  • Singleton 不可以被实例化,而是直接调用其 getInstance( ) 等函数(往往是静态函数)来返回唯一实例
  • Singleton 经常和 Factory 一起使用,因为一般来说工厂对象只需要一个

请添加图片描述

Builder:当我们要创建的对象很复杂的时候(通常是由很多其他的对象组合而成),我们要将复杂对象的创建过程和这个对象的表示(展示)分离开来,由于在每一步的构造过程中可以引入参数,使得经过相同的步骤创建最后得到的对象的展示不一样。

  • Builder 的关键是 Director 对象并不直接返回对象,当然也可以提供一个默认的返回对象的接口(即返回通用的复杂对象的创建,即不指定或者特定唯一指定 BuildPart 中的参数)
  • Builder 和 AbstractFactory 很相似,都是用来创建大的复杂的对象。 Builder 强调一步一步创建对象,并且可以通过相同的创建过程可以获得不同的结果对象,并且不直接返回对象;AbstractFactory 强调的是为创建多个相互依赖的对象提供一个统一的接口。

请添加图片描述

Prototype 模式:新对象的创建可以通过已有对象进行创建,其他于语言常有 clone() 或 copy( ) 函数,在 C++ 中由拷贝构造函数来实现。

  • 这里 Prototype 本身就是对象工厂,与前面几个工厂不同,prototype 强调从自身复制自己创建新类。

请添加图片描述

结构型模式

Bridge:使用组合(委托)的方式将抽象和实现彻底地解耦,抽象和实现可以独立地变化,减少因为需求变化而导致类的迅速膨胀。

  • Bridge 的关键是在于 “favor composition over inheritance” ,即 pImpl 方法代替继承。

请添加图片描述

Adapter:转换器,我们已经实现的接口通过接口转换得到一个第三方的接口,例如 C++ 中的 stack 和 queue,实际上底层可以是 vector、list、deque 等;常有两种实现方法:类模式和对象模式,区别在于是 inheritance 还是 composition

请添加图片描述

请添加图片描述

Decorator:需要为一个已经定义好的类添加新的职责,但是又不想修改类,也不想继承某一个具体的类,就可以考虑使用 decorator;

  • 注意图示里的 Operation() 被装饰以后,我们调用 Operation 的同时也会执行 addedBehavior()
  • decorator 和 proxy 模式都会有一个指向其他对象的引用/指针,但 Proxy 模式会提供使用其作为代理的对象统一的接口,使用代理类将其操作都委托给 Proxy 直接进行,其实是组合和委托之间的微妙区别。

请添加图片描述

Composite:递归构建树状的组合结构(有点像广义表),每个 composite 里边可以有多个 component,每个 component 可以是具体的实现(如 Leaf),也可以是又一个 composite

  • Composite 和 Decorator 的模式结构图类似,但是 Composite 模式旨在构造类,而 Decorator 模式重在不生成子类即可给对象添加职责

(图里错了,leaf 右边的是 composite 类)

请添加图片描述

Flyweight :将对象的状态分为内部状态和外部状态,内部状态可以被共享、不会变化,存储在对象中;而外部状态可以适当的时候作为参数传递给对象。

  • 例如一个字母“a”在文档中出现了若干次,可以让这些字符共享“a”一个对象,其字体大小等可以作为参数传入。
  • Flyweight 模式在实现过程中主要是要为共享对象提供一个存放的“仓库”(对象池),我觉得有点像 Java 处理 String 的方式,上面的解释反而使得 Flyweight 的意思更抽象了hhh

请添加图片描述

Facade :就有点像是我们要完成一件事情,这个事情由不同的步骤组成,而这些步骤的实现方法都分布在不同的类中,那么我们可以写一个类,将各个类都包裹起来,然后只对外维护一个接口,这样我们只需要调用这个接口,内部就可以自动地调用其他类的方法依次完成这件事情。

  • Facade 在高层提供了一个统一的接口,解耦了系统

请添加图片描述

Proxy: 以下问题适合使用 Proxy 模式

  • 创建开销大的对象时,比如显示一幅大的图片,我们将这个创建的过程交给代理去完成
  • 为网络上的对象创建一个局部的本地代理,我们将这个操纵的过程交给一个代理去完成
  • 对对象进行控制访问的时候,比如论坛上不同权限的用户,将这个工作交给一个代理去完成
  • 智能指针

Proxy 模式最大的好处就是实现了逻辑和实现的彻底解耦

请添加图片描述

行为模式

Template :采用继承的方法,将某一处理问题的逻辑框架放在抽象基类中,并且定义好细节的接口,而在子类中实现每一个步骤的实现细节。

  • 本质上就是使用多态的方法实现算法实现细节和高层接口的松耦合。(想一下侯捷大佬举的操作系统的例子)

  • Template 模式体现了 DIP(依赖倒置原则),其含义就是父类调用子类的操作。

  • 相比于 Strategy,Template 的问题就是继承固有的问题,但相应地 Strategy 付出了空间和时间上的代价

请添加图片描述

Strategy:Strategy 要解决的问题和 Template 是一样的,但是逻辑被封装到 Context 类里(而 Template 的逻辑封装在 AbstractClass 里),通过组合的方式将具体算法的实现在组合对象中实现

  • Strategy 模式和 Template 模式实际是实现一个抽象接口的两种方式:继承和组合之间的区别,但还是优先使用组合
  • Strategy 模式很 State 模式也有相似之处,但是 State 模式注重的对象在不同的状态下不同的操作。两者之间的区别就是 State 模式中具体实现类中有对 Context 的函数的引用,而 Strategy 模式则没有。

请添加图片描述

组合

  • 优点
    1. “黑盒”复用,因为被包含对象的内部细节对外是不可见的;
    2. 封装性好,原因为 1.;
    3. 实现和抽象的依赖性很小(组合对象和被组合对象之间的依赖性小);
    4. 可以在运行期间动态定义实现(通过一个指向相同类型的指针,典型的是抽象基类的指针)。
  • 缺点
    1. 系统中对象过多。

继承

  • 优点
    1. 易于修改和扩展那些被复用的实现。
  • 缺点
    1. 破坏了封装性,继承中父类的实现细节暴露给子类了;
    2. “白盒”复用,原因在 1. 中;
    3. 当父类的实现更改时,其所有子类将不得不随之改变
    4. 从父类继承而来的实现在运行期间不能改变(编译期间就已经确定了)。

State:需要对不同的状态作出不同的响应,同时分离状态逻辑和动作(而不是像 switch-case 一样全部写在一起)

  • 将 State 声明为 Context 的友元类(friend class),这样才可以切换状态
  • State 及其子类中的操作都将 Context*传入作为参数(传入 this 指针)

请添加图片描述

Observer:MVC 就是一种 Observer 模式,发布-订阅,目标是通知的发布者,观察者是通知的订阅者

  • Subject 中有一个保存指向 Observer 引用的数组,可以发布消息,调用每个 Oberver 的 update

请添加图片描述

Memento:不破坏封装性的前提下,捕获并保存一个类的内部状态,这样就可以利用保存的状态实施恢复操作(撤销/Undo 的动作)

  • Memento 模式的关键就是 friend class Originator,并且 Memento 的接口都设为 private ,这样 Originator 就可以访问到所有东西,保证了封装性
  • Memento 相当于是 Originator 的一个备份
  • 在 Command 模式中,Memento 模式经常被用来维护可以撤销操作的状态

请添加图片描述

Mediator :将对象间的交互和通讯封装在一个类中,个对象间的通信不用显示声明引用,大大降低了系统的复杂性能,带来了系统对象间的松耦合。

  • 每个 Colleague 维护一个 Mediator,将多对多的通信转化为一对多的通信;A、B 和 Mediator 之间需要双向绑定

请添加图片描述

Command:将请求封装到一个对象(Command)中,并将请求的接收者存放到具体的 ConcreteCommand 类中(Receiver),从而实现调用操作的对象和操作的具体实现者之间的解耦。

  • Command 类中一般就是只是一些接口的集合,并不包含任何的数据属性
  • 在 Command 要增加新的处理操作对象很容易,我们可以通过创建新的继承自 Command 的子类来实现这一点。
  • Command 模式可以和 Memento 模式结合起来,支持取消的操作

请添加图片描述

Visitor:在面对需求更新时,将更新封装到一个类中(访问操作),并由待更改类提供一个接受接口

  • 这里 Element 是待更改的类,Visitor 是更新的内容
  • Visitor 的关键是双分派,双分派意味着执行的操作将取决于请求的种类和接收者的类型;而 C++ 是单分派,可以通过 RTTI 来实现
  • 问题:破坏了封装性,从外部可以修改 Element 对象的状态,要不然就要 Element 提供足够的 public 接口,要不然要声明 friend Visitor;ConcreteElement 的扩展很困难,每增加一个 Element 的子类,就要增加 Visitor 的接口

请添加图片描述

Chain of Responsibility:将可能处理一个请求的对象链成一个链,并且将请求在链上传递,直到有对象处理该请求(可能需要提供一个默认处理所有请求的类)

  • 这里 Handler 可以相互链接成链表,每次接到请求首先看看自己可不可以处理,如果不行,就交给后继节点处理
  • Chain of Responsibility 模式的最大的一个有点就是给系统降低了耦合,请求的发送者完全不必知道该请求会被哪个应答对象处理

请添加图片描述

Iterator:将一个聚合对象的遍历问题封装到一个类中进行,避免暴露这个聚合对象的内部表示,比如 C++ 容器的迭代器

  • 为了更好地保护 Aggregate 的状态,可以尽可能减少它的 public 接口,而通过将 Iterator 对象声明为 Aggregate 的友元来给予Iterator一些特权,获得访问 Aggregate 私有数据和方法的机会

请添加图片描述

Interpreter:使用一个解释器,为用户提供一个一门定义语言语法表示的解释器,然后通过这个解释器来解释语言中的句子。(可以想想编译器的前端)

  • Interpreter 模式中使用类来表示文法规则,因此可以很容易实现文法的扩展,可以使用 Flyweight 模式来实现终结符的共享

请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Air浩瀚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值