设计模式笔记

东南大学设计模式课程笔记。考试时间12月9日,开卷考试

1. Design Pattern

首先,讨论(设计)模式是什么

  • 模式:每个模式是一条由三个部分组成的规则,它表示了一个特定环境、一个问题和一个解决方案之间的关系。更具体来说,包括模式名称、问题、解决方案、效果。例如:模型-视图-控制器(MVC,Model-View-Controller)

例如:

  • 特定环境:开发人机界面软件
  • 问题:开发时,用户界面应易于改变。修改或移植界面不应该影响程序功能核心代码
  • 解决方案:交互程序划分为处理输出输入。MVC格式为: 模型:组件封装核心数据和功能 视图:组件给用户显示信息,视图获得模型提供的待展示数据 控制器:每个视图都有一个相关控制器组件。输入是鼠标、键盘指令,事件被转换为服务请求,服务请求被发送给模型或视图

那么,模式到底是啥呢?

  • 一个模式关注一个特定环境中出现的重现设计问题,并提供一个解决方案
  • 模式是一种抽象,是设计经验,有助于构建复杂异构软件体系,有助于管理软件复杂度

模式有啥用呢?

  • 提高重用
  • 接口与实现分离
  • 降低耦合

如何描述一个模式?可以从下面的角度来

  • 设计模式名
  • 问题:待解决的设计问题描述
  • 意图:设计模式是什么?基本原理和意图是什么?解决的是什么样的特定设计问题?
  • 动机:用以说明一个设计问题以及如何用模式中的类、对象来解决该问题的特定情景
  • 适用性:什么情况下可以使用该设计模式?该模式可用来改进哪些不良设计?怎样识别这些情况
  • 解决方案
  • 效果:模式怎样支持它的目标?使用模式的效果和所需做的权衡取舍?系统结构的哪些方面可以独立改变?
  • 例子

模式类型,根据目的准则,分为三种:

  • 创建型模式:创建对象
  • 结构型模式:组合类或对象
  • 行为型模式:描述对象交互和职责 image-20201118151120859

模式类型,根据范围准则,分为两种:

  • 类模式:处理类和子类的关系。是静态的
  • 对象模式:处理对象间的关系。是动态的

两种分类可以结合使用

image-20201118153428860

模式与框架有啥关系呢?

  • 模式:模式支持软件结构和设计的重用。模式是成功解决方案的静态、动态结构和相互协作的结合,是一种抽象。如MVCFactory Method
  • 框架:支持细节设计和代码的重用。框架是一组组件的结合,这些组件相互合作,为一个应用提供可重用的结构。实现框架超类的抽象方法来实现重构。如MMCMS Script Engine
  • 设计模式比框架更抽象,更广泛性,是更小的架构元素
  • 模式与框架结合,能提高软件质量。包括:重用性扩展性性能可维护性

设计模式解决实际问题步骤,包括:

  • 寻找合适对象
  • 决定对象粒度
  • 指定对象接口
  • 描述对象实现(接口继承与类继承,对接口编程,而不是对实现编程)
  • 运用复用机制(优先使用对象组合,而不是类继承)
  • 设计应支持变化 image-20201118154306235 image-20201118154316699

2. Pattern-Oriented Software Architecture

面向模式的软件架构Pattern-Oriented Software Architecture,POSA

POSA里面的模式包括:

  • 架构模式Architecture Patterns:架构模式是软件系统的基本结构组织形式或结构方案。包含预定义子系统、子系统责任、用于管理的规则和向导。如:MVC
  • 设计模式Design Patterns:设计模式是软件系统的精炼解决方案。包含特定环境下解决特定问题的可重现结构。如Observer
  • 惯用法Idioms:惯用法是一个与编程语言相关的低级模式。描述了如何实现组件功能

架构模式是一种非常高层次的模式。架构模式包括:

  • 组织组件Organize components:组织组件负责内容结构化。包括层Layer、管道和过滤器Pipes and Filters(处理数据流的系统使用,例如编译器)、黑板Blackboard(不同系统用同一套数据结构,例如分布式系统)
  • 分布式系统Distributed Systems:分布式系统可以处理分布式计算。包括经纪人Broker(客户端和服务端中间的处理部件,用于解耦)
  • 交互系统Interactive System:交互系统让程序功能核心独立于用户界面。包括Model-View-Controller, MVC(把应用分为处理、输入、输出。业务模型、用户界面、控制器。其中ViewController一般是观察者Observer模式?)、Presentation-Abstract-Control, PAC(把应用分层,或分为类似MVC的组件,低层服务高层,最高层只有一个组件)
  • 自适应系统Adaptable System:自适应系统适合频繁变化。包括微内核Microkernel(封装应用基本服务)、反映Reflection

设计模式包括:

  • 结构拆解Structure Decomposition:结构拆解有系统拆为子系统、大组件拆为协同工作的小组件。包括整体-局部Whole-Part(封装小对象,提供访问接口)
  • 工作组织Organization of Work:工作组织用于组件合作解决问题。包括主从结构Master-Slave(主拆分大任务给从,并合并从返回的答案)
  • 访问控制Access Control:访问控制可以控制访问服务和组件。包括代理模式Proxy Pattern(代理与客户交互,实现访问控制)
  • 管理Management:管理可以处理同类型的内容。包括命令处理器Command Processor、视图处理器View Handler
  • 交互Communication:交互负责组件间的交流。包括接收器-转发器Forwarder-Receiver(提供分布式组件的交互)、客户端-调度器-服务器Client-Dispatcher-Server、发布者-订阅者Publisher-Subscriber

惯用法,又叫编程模式Programming Pattern,例如:计数指针Counted PointerVirtual constructorsmart pointer

设计模式可以参考GoF23个设计模式,包括:

  • 创建型模式Creational Patterns。提供了一种在创建对象的同时,隐藏创建逻辑的方法,而非仅仅用new运算符直接实例化对象,使程序判断实例需要创建什么对象时更加灵活。包括:工厂模式Factory Pattern、抽象工厂模式Abstract Factory Pattern、建造者模式Builder Pattern、单例模式Singleton Pattern、原型模式Prototype Pattern
  • 结构型模式Structural Patterns。关注类和对象的组合,继承的概念被用来组合接口和定义组合对象获得新功能的方式。包括:适配器模式Adapter Pattern、桥接模式Bridge Pattern、过滤器模式Filter\Criteria Pattern 、组合模式Composite Pattern、装饰器模式Decorator Pattern、外观模式Facade Pattern、享元模式Flyweight Pattern、代理模式Proxy Pattern
  • 行为型模式Behavioral Patterns。关注对象之间的通信。包括:责任链模式Chain of Responsibility Pattern、命令模式Command Pattern、解释器模式Interpreter Pattern、迭代器模式Iterator Pattern、中介者模式Mediator Pattern、备忘录模式Memento Pattern、观察者模式Observer Pattern、状态模式State Pattern、空对象模式Null Object Pattern、策略模式Strategy Pattern、模板模式Template Pattern、访问者模式Visitor Pattern

此外,还有J2EE设计模式,是Sun Java Center提出的8种补充设计模式:

  • MVC模式MVCPattern
  • 业务代表模式Business Delegate Pattern
  • 组合实体模式Composite Entity Pattern
  • 数据访问对象模式Data Access Object Pattern
  • 前端控制器模式Front Controller Pattern
  • 拦截过滤器模式Intercepting Filter Pattern
  • 服务定位器模式Service Locator Pattern
  • 传输对象模式Transfer Object Pattern

设计模式原则,包括6点:

  • 开闭原则Open Close Principle:对扩展开放,对修改关闭。需要接口和抽象类
  • 里氏代换原则Liskov Substitution Principle:任何基类可以出现的地方,子类一定可以出现
  • 依赖倒转原则Dependence Inversion Principle:针对接口编程,依赖抽象而不依赖具体
  • 接口隔离原则Interface Segregation Principle:使用多个隔离的接口,比使用单个接口好。含义是
  • 迪米特原则Demeter Principle
  • 合成复用原则Composite Reuse Principle

3. Creational Patterns

创建型模式Creational Patterns抽象了实例化过程,帮助系统独立于如何创建、组合和表示对象。类创建型模式用继承改变类,对象创建型模式将实例化委托给对象

创建型模式包括:Factory MethodAbstract FactoryBuilderPrototypeSingletonFinder

工厂模式包括:

  • 简单工厂(Simple Factory)模式 image-20201206110032116
  • 工厂方法(Factory Method)模式
  • 抽象工程(Abstract Factory)模式

工厂方法Factory Method

  • 别名:虚拟构造函数Virtual Constructor
  • 意图:定义一个创建对象接口,子类决定实例化哪个类 image-20201206110047867
  • 动机:抽象类
  • 适用性:类不知道子类应该是哪个时;应该由子类决定时;将抉择委托给子类时
  • 结构: ![image-20201118155416500](C:\Users\Blue Stragglers\AppData\Roaming\Typora\typora-user-images\image-20201118155416500.png)
  • 参与者: image-20201118155902032
  • 协作:依赖于子类实现,返回一个ConcreteCreator实例
  • 效果:优点:多态性(客户代码可以与特定应用无关),增加了灵活性;缺点:需要增加类数
  • 实现:父类提供缺省实现;
  • 相关模式:抽象工厂Abstract FactoryPrototype
  • 例子: image-20201118155519851

抽象工厂Abstract Factory

  • 意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
  • 动机:为了解决一族相关或者相依对象的创建工作,专门定义一个用于创建这些对象的接口(基类)。客户只需与这个基接口打交道,不必考虑实体类的类型 image-20201206110103971
  • 适用性: image-20201118160818310
  • 结构:
  • 参与者: image-20201118160837974
  • 协作: image-20201118160848514
  • 效果:是多个工厂模式的合并,要求工厂模式是virtualimage-20201118161004120
  • 实现: image-20201118161122706
  • 相关模式:FactoryPrototypeSingleton
  • 例子: image-20201118161203839

生成器模式Builder

  • 意图:将复杂对象的构造与其表示分开,以便相同的构造过程可以创建不同的表示
  • 动机:复杂对象构造过程中,可以同样的构造过程加入不同元素。也就是:结构化构造过程 image-20201206110001659
  • 适用性: image-20201118161612429 image-20201206105819549
  • 结构: image-20201118161621097
  • 参与者: image-20201118161638375
  • 协作: image-20201118161655256 image-20201206105905801 image-20201206105917130
  • 效果:可以更改内部表示;分隔了构造和表示的代码;更好控制构建过程 image-20201206105803641
  • 实现:构造接口、空方法
  • 相关模式:Abstract Factory。区别在于,Builder重点关注构造,能构造复杂对象
  • 例子: image-20201118162005789

原型模式Prototype

  • 意图:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象
  • 动机:以一个已有的对象作为原型,通过它来创建新的对象。在增加新的对象的时候,新对象的细节创建工作由自己来负责,从而使新对象的创建过程与框架隔离开来
  • 适用性: image-20201118162221256
  • 结构: image-20201118162230006
  • 参与者:Prototype、ConcretePrototype、Client image-20201118162312765
  • 协作:客户请求一个原型克隆自身
  • 效果: image-20201118162427240
  • 实现: image-20201118163302729
  • 相关模式:Abstract Factory(竞争关系)、Factory
  • 例子: image-20201118163350297

单例模式Singleton

  • 意图:确保一个类只有一个实例,并提供对其的全局访问点
  • 动机:对于某些类,只有一个实例很重要。如实例控制的类
  • 适用性:必须有一个类的一个实例,并且必须可以从众所周知的访问点访问它。当唯一的实例应该可以通过子类扩展,并且客户端应该能够使用扩展的实例而无需修改其代码。
  • 结构: image-20201119122548498
  • 参与者:Singleton
  • 协作:客户端仅通过SingletonInstance操作访问Singleton实例
  • 效果: image-20201119125820884
  • 实现: image-20201119125934260
  • 相关模式: image-20201119125953407
  • 例子:MFC中的CWinApp派生类实例theApp

Finder

  • 别名:Object-retriever
  • 意图:利用环境信息,根据客户的请求,找到已有的、符合要求的对象,返回给客户
  • 动机:Finder根据状态标识信息,返回已经被创建的对象,如果没有查询对象,应该创建新对象
  • 适用性:该应用程序要求用户自定义在浏览器中遇到特定文件格式时采取的操作
  • 结构: image-20201119131101862
  • 参与者:clientfinderproduct-tableconstructorproduct
  • 协作:
  • 效果: image-20201119131154570
  • 实现: image-20201119131324917
  • 相关模式:SingletonPrototype
  • 例子:moniker in COM

Creation patterns 小结:

采用 Abstract Factory、Builder 和 Factory 模式可以分离接口和具体实现。但有所区别,如下例子:

  • Factory 类似购买品牌机,F 提供品牌机,用户按需求购买。
  • Builder 类似购买组装机,客户提要求,Builder 构建机器。
  • Abstract Factory 类似 DIY,AF 提供零件,客户自己组装。

Prototype 通过 Product 原型来构造 product,需要 clone + prototype manager。

Singleton 是单实例类型,提供构造和访问的方法。

Finder 把对象的获取过程和客户隔离开。

Factory Method、abstract factory、Prototype 都涉及到类层次结构中对象的创建过程,但有所区别:

  • Prototype 需要 Prototype Manager。
  • Factory Method 需要依附一个 Creator 类。
  • Abstract Factory 需要一个平行的类层次。
  • 可以根据应用的其他需求,以及语言的便利程度,来决定使用哪种构造设计模式。

Builder 往往适合于特定的结构需要,它所针对的 product 比较复杂。

Singleton 有较强的物理意义,可以用在许多地方,不一定与类层次关联。

Finder 需要有一定范围的对象管理功能。

有时需要结合几种构造模式,同时完成一项任务。

4. Structural Patterns

Structural Patterns内容包括:

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Facade
  • Flyweight
  • Proxy

结构模式目标是组合类和对象,构造更大的结构。

  • 类模式采用继承机制组合接口或实现。
  • 对象模式采用了其他方法,组合对象。

Adapter 模式

别名:Wrapper

意图:将一个类接口转换成客户希望的另一个接口。从而使因为接口不兼容而不能共同工作的类协同工作。

动机:有时,专为重用而设计的工具箱类仅因其接口与应用程序所需的特定于域的接口不匹配而无法重用。

适用范围:

  • 您想要使用现有的类,并且其接口与您需要的接口不匹配。
  • 您想创建一个可重用的类,与不相关或无法预料的类配合使用,即,不一定具有兼容接口的类。
  • (仅对象适配器)您需要使用几个现有的子类,但是通过对每个子类进行子类化来适配它们的接口是不切实际的。 对象适配器可以调整其父类的接口。

结构:

image-20201206113532075

参与者:Client、Target、Adaptee、Adapter

协同:

  • class adapter —— delegation
  • object adapter —— container

评价:本质上是两种重用模型,类适配器和对象适配器。类适配器需要重载,对象适配器不需要。双向适配器可以提供透明性。类适配器可以多重继承。

实现:

image-20201206113924859

相关模式:

  • Bridge
  • Decorator
  • Proxy

样例:

  • DrawCli:COleDrawObj
  • C++ STL
  • COM中的site

Bridge 模式

别名:Handle / Body

意图:将抽象部分和实现部分分离,使他们都能独立变化,但还能够动态地结合。

动机:要实现抽象(接口)与实现(行为)分离,最常用的方法就是定义一个抽象类,然后在子类中提供实现。也就是,用继承方式实现。但这种方法不够灵活。因此,采用 Bridge 模式。

适用范围:

  • 编译时刻无法确定抽象(接口)与实现之间的关系
  • 抽象部分与实现部分都可以通过子类化而扩展
  • 对一个实现的修改不影响客户(无须重新编译)
  • 在 C++ 中,对客户完全隐瞒实现细节
  • 因为扩展的原因,需要把一个类分成两部分,(以便灵活组合)
  • 在多个对象之间共享数据,但客户不需要知道

结构:

image-20201206114422058

参与者:

  • Client
  • Abstraction —定义抽象类的接口,维护一个指向 Implementor 类型对象的指针.
  • RefinedAbstraction —扩充由 Abstraction 定义的接口
  • Implementor
  • ConcreteImplementor

评价:抽象部分和实现部分有分离,可以在运行时刻连接起来。可以提高可扩充性,抽象部分和实现部分可以分别扩充。对用户隐藏实现细节。

实施:只有一名实施者,实施者对象通过语言或工厂模式创建,资源管理采用计数技术,使用多重继承。

相关模式:Abstract Factory 可以用来创建和配置 Bridge 模式

样例:handle:文件 handle、窗口 handle

Composite 模式

意图:将对象以树形结构表示为“部分-整体“的层次结构。

动机:经过组合后的对象可以提供单个部件接口,即”容器“。

适用性:

  • 您想要表示对象的整体层次结构。
  • 您希望客户能够忽略对象组成和单个对象之间的差异。 客户将统一对待复合结构中的所有对象。

结构:

image-20201206115431007

参与者:Client、Component、Leaf 、Composite

评价:定义了由原始对象和复合对象组成的类层次结构。定义了包含叶对象和复合对象的类层次接口。——递归结构。使客户变得简单,客户一致地处理复合对象和细分对象。使添加新类型的组件变得更加容易。可能会使您的设计过于笼统。某些系统过度一般化,无法限制类型的组合,可以在运行时刻通过类型检查合并。

实施:明确的父母参考,共享组件,最大化组件接口,宣告子代管理操作,组件应该实现组件列表吗?子序列,缓存以提高性能,谁应该删除组件?存储组件的最佳数据结构是什么?

相关模式:Decorator、Flyweight、Iterator、Visitor

样例:广泛应用于OO领域,MFC中的CWnd,组件层次:ActiveX Container

Decorator 模式

别名:油漆工模式

意图:动态给对象添加一些额外的职责,就像油漆工刷漆。使用 Decotator 模式比生成子类方法实现功能扩充更灵活。

动机:Decotator 实现了功能扩展的即插即用。

结构:

image-20201206162355684

参与者:抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。

Facade 模式

意图:为子系统中的一组接口提供一个一致的界面。

动机:使各个子系统间的关联最小。Facade对象为子系统提供一个简单的、泛化的设施。

应用:

  • 为一个复杂的子系统提供一个简单接口时运用Facade模式.子系统往往会非常复杂,但是其接口应该尽可能地简单,特别是对于一般用户而言
  • 客户与抽象类的实现部分之间必然存在一定的依赖性,Facade可以降低这种依赖性
  • 在多个子系统的结构中,使用Facade模式定义子系统的入口点,有助于降低各子系统之间的依赖性

结构:

image-20201206115744447

参与者:Facade、Subsystem classes

评价:简化子系统的接口,方便客户使用子系统;化“紧耦合”为“松耦合”
—— 实现组件软件的关键技术;facade模式并不限制客户直接访问子系统的内部类和对象。

实施:以抽象类的形式定义facade,进一步decouple,从而完全隔离子系统的细节。公共子系统子系统与私有子系统子系统。

相关模式:Facade对象创建涉及了singleton、abstract factory。

Flyweight 模式

别名:享元模式

意图:运用共享技术有效地支持大量细粒度对象。

动机:对象粒度太小时,大量对象会浪费资源。

应用:应用程序使用大量对象。由于对象数量巨大,因此存储成本很高。大多数对象状态可以是外部的。一旦删除了外部状态,许多对象组可能会被相对较少的共享对象所代替。该应用程序不依赖于对象标识。 由于可以共享轻量对象,因此对于概念上不同的对象,身份测试将返回true。

结构:

image-20201206161803285

参与者:client, flyweight, concreteFlyweight, FlyweightFactory, UnsharedConcreteFlyweight

评价:把对象的状态分开:intrinsic and extrinsic。节约存储空间:内部状态的共享节约了大量空间,外部状态可通过计算获得从而进一步节约空间。flyweight 与 composite 结合。Flyweight为leaf节点,并且父节点只能作为外部状态。

实现:删除额外状态,尽可能做到实时计算(通过一个小的数据结构)。管理共享对象,客户不能直接实例化flyweight,必须通过管理器,例如FlyweightFactory。flyweight的生命周期管理,引用计数和回收。

相关模式:可以与 Composite 模式相结合。可以用 flyweight 实现 State 和 Strategy 模式中的对象。

样例:Excel中cell的管理,“Design Patterns”中提到的文档编辑器的例子。

Proxy 模式

意图:为其他对象提供一种代理,以控制对这个对象的访问。

动机:提供一种授权机制。

结构:

image-20201206162527377

Structural Patterns 小结

Adapter、Bridge、Facade 之间存在区别:

  • Adapter 用于在两个不兼容的接口之间进行转换。
  • Bridge 用于将一个抽象与多个可能的实现连接起来。
  • Facade 用于将复杂的子系统定义为一个新的简单易用的接口。

Composite、Decorator、Proxy 之间存在区别:

  • Composite 用于构造对象组合结构。
  • Decorator 用于为对象增加新的职责。
  • Proxy 为目标对象提供一个替代者。

Flyweight :是针对细粒度对象的一种全局控制手段。

5. Behavioral Patterns

Behavioral Patterns 行为模式,是在不同对象之间划分责任和算法的抽象化。行为模式不仅是类和对象间的,还关乎它们的相互作用。分为类的行为模式(CBP)和对象的行为模式(OBP),分别采用类的继承,以及对象的聚合来分配行为。

行为模式包含内容:

  • Chain of responsibility
  • Command
  • Iterator
  • Observer
  • Visitor
  • Strategy
  • Mediator
  • Memento
  • State
  • Template Method
  • Interpreter

Chain of Responsibility 模式

意图:使多个对象有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。

Command 模式

别名:行动模式,交易模式

意图:命令模式把一个请求或操作封装到一个对象中,是对命令的封装。

Iterator 模式

意图:提供一种顺序访问对象中各个元素的方法,又不需要暴露对象的内部表示。

Observer 模式

别名:发布-订阅模式,从属模式等。

意图:定义了一种一对一关系,让多个观察者对象同时监听一个主题对象,主题对象变化时会告诉所有观察者对象,让他们更新自己。

Strategy 模式

意图:定义一系列算法,并将算法封装成类。

Visitor 模式

意图:封装施加于某种对象结构中各个元素上的操作,也就是将方法和数据结构分离开了。

Interpreter 模式

意图:给定一个语言,定义它文法的一种表示,并建立一个解释器解释其中的句子。

Mediator 模式

意图:用中介者对象封装一系列关于对象交互的行为。

Memento 模式

别名:Token

意图:不破坏封装性的前提下,捕获一个对象的内部状态。

State 模式

意图:允许一个对象在内部改变时改变行为。

Behavioral Patterns小结

Strategy、Iterator、Mediator、State、Command 模式,都用一个对象来封装某些特性,如:变化、交互、状态、行为、命令。

Mediator、Observer 模式,能够建立主从对象间的松耦合连接。

Command、Chain of Responsibility、Interpreter 模式有所区别:

  • Command 模式倾向于命令总体管理。
  • Chain of Responsibility 模式倾向于命令被正确处理。
  • Interpreter 模式用于复合结构中操作的执行过程。