编程设计:设计模式
站内链接:
1. Classify
UML 类图
- 关联关系: 表示对象之间的引用关系, 用于表示一类对象与另一类对象的关系,其可以分为单向关联、双向关联
- 单向关联:
一个带箭头的实线
- 双向关联:
一个无箭头的实线
,双方各自持有对方类型的成员变量 - 自关联:
一个指向自身的箭头实线
,类自身包含自身类对象实例
- 聚合关系: 这是关联关系的一种,这是强关联,表示整体和部分之间的关系,其中对象可以脱离整体独立存在,
带空心菱形的实线来表示
- 组合关系:这也是关联关系的一种,这是更强关联,也是表示整体和部分的关系,但是部分对象不可以脱离整体独立存在,
带实心菱形的实线来表示
- 依赖关系:这是一种使用关系,这是对象间耦合度最低的关联方式,通过局部变量或方法参数来访问被依赖类的某个功能,
带箭头的虚线来表示
- 继承关系:
带空心三角箭头的实线来表示
- 实现关系:这是接口和实现类之间的关系,
带空心三角箭头的虚线来表示
七大原则
- 单一职责原则(Single Responsibility Principle,SRP):一个类应该只有一个引起它变化的原因,即一个类应该只负责一项职责。
- 开放封闭原则(Open-Closed Principle,OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。即通过扩展已有代码来实现变化,而不是修改已有代码。
- 里氏替换原则(Liskov Substitution Principle,LSP):子类必须能够替换它们的基类,而不会影响程序的正确性。即子类应该能够在不破坏程序正确性的情况下扩展基类的功能。
- 依赖倒置原则(Dependency Inversion Principle,DIP):高层模块不应该依赖低层模块,它们都应该依赖于抽象。即应该通过接口或抽象类来定义高层模块和低层模块之间的依赖关系。
- 接口隔离原则(Interface Segregation Principle,ISP):一个类不应该依赖于它不需要使用的接口。应该将大接口拆分成多个专门的小接口,客户端只需关注它们需要使用的接口。
- 迪米特法则(Law of Demeter,LoD):一个对象应该对其他对象有尽可能少的了解,只与直接的朋友进行通信。即减少对象之间的耦合性,尽量降低类与类之间的依赖关系。
- 合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP):优先使用对象组合(合成)或聚合关系来达到复用的目的,而不是通过继承来达到复用。
分类
设计模式分为三种类型,共 23 类:
- 创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、简单工厂模式、原型模式。
- 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
- 行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
将这么多模式做成一个表格,其输出如下:
模式 | 类型 | 功能介绍 |
---|---|---|
工厂模式 (Factory Pattern) | create | 通过工厂方法创建对象,将对象的创建与使用分离,使得代码更灵活、可扩展。 |
抽象工厂模式 (Abstract Factory Pattern) | create | 提供一个接口来创建一系列相关或相互依赖的对象,而无需指定具体的类。 |
单例模式 (Singleton Pattern) | create | 确保一个类只有一个实例,并提供全局的访问点,常用于控制资源的共享访问。 |
建造者模式 (Builder Pattern) | create | 将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。 |
原型模式 (Prototype Pattern) | create | 通过复制现有对象来创建新的对象,避免了对象的频繁创建和销毁,提高了性能和代码复用。 |
适配器模式 (Adapter Pattern) | struct | 将一个类的接口转换为客户端所期望的另一种接口,使得原本不兼容的接口能够协同工作。 |
装饰器模式 (Decorator Pattern) | struct | 动态地为对象添加额外的功能,不修改其原始类的结构,而是通过组合来扩展对象的功能。 |
外观模式 (Facade Pattern) | struct | 提供一个统一的接口,封装一组复杂的子系统接口,简化客户端与子系统之间的交互,降低耦合度。 |
代理模式 (Proxy Pattern) | struct | 通过代理对象控制对另一个对象的访问,可以在访问对象前后增加额外的操作,提供更加灵活和安全的访问方式。 |
桥接模式 (Bridge Pattern) | struct | 将抽象部分与其具体实现部分分离,使它们可以独立地变化,提高了系统的灵活性和可扩展性。 |
组合模式 (Composite Pattern) | struct | 将对象组合成树形结构以表示“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。 |
享元模式 (Flyweight Pattern) | struct | 共享细粒度对象,通过共享减少内存使用,提高系统的性能和效率。 |
观察者模式 (Observer Pattern) | behavior | 定义了对象之间的一种一对多的依赖关系,当一个对象状态改变时,它的所有依赖者都会收到通知并自动更新。 |
策略模式 (Strategy Pattern) | behavior | 定义一系列算法,将每个算法封装起来,并使它们可以相互替换,使得算法可以独立于使用它的客户端进行变化。 |
命令模式 (Command Pattern) | behavior | 将请求封装成对象,将发送者和接收者解耦,支持撤销操作、队列请求等功能。 |
模板方法模式 (Template Method Pattern) | behavior | 定义一个算法的骨架,将具体步骤的实现延迟到子类中,使得子类可以重新定义算法的某些步骤,而不改变算法的结构。 |
迭代器模式 (Iterator Pattern) | behavior | 提供一种统一的方法顺序访问一个聚合对象中的各个元素,而无需暴露其内部表示。 |
状态模式 (State Pattern) | behavior | 允许对象在其内部状态改变时改变其行为,将不同的状态封装成独立的类,并使其可以相互转换,提高了系统的灵活性和可维护性。 |
责任链模式 (Chain of Responsibility Pattern) | behavior | 将请求从发送者到接收者进行解耦,每个处理器都有机会处理请求,直到找到合适的处理器。 |
中介者模式 (Mediator Pattern) | behavior | 通过一个中介对象封装一系列对象之间的交互,使对象之间的通信更松散、更易于维护和扩展。 |
访问者模式 (Visitor Pattern) | behavior | 封装对某个对象结构中各元素的操作,可以在不改变这些元素的类的前提下定义新的操作,提高了系统的灵活性和可扩展性。 |
解释器模式 (Interpreter Pattern) | behavior | 定义了一个语言的语法表示,并定义一个解释器来解释这个语法,用于处理特定类型的语法分析和处理。 |
备忘录模式 (Memento Pattern) | behavior | 在不违背封装原则的前提下,捕获对象的内部状态并在对象之外保存这个状态,以便在之后恢复对象到先前的状态。 |
使用场景
模式 | 适用场景 |
---|---|
工厂模式 (Factory Pattern) | 对象的创建逻辑复杂,需要统一管理和控制对象的创建过程,以及提供灵活的扩展能力。 |
抽象工厂模式 (Abstract Factory Pattern) | 需要创建一系列相关或相互依赖的对象,且不希望暴露具体实现类,而是通过抽象工厂来创建对象。 |
单例模式 (Singleton Pattern) | 需要确保一个类只有一个实例,并提供全局的访问点,常用于控制资源的共享访问。 |
建造者模式 (Builder Pattern) | 创建一种类型的复杂对象,通过设置不同的可选参数进行定制化,避免构造函数参数过多和构造方法重载的问题。 |
原型模式 (Prototype Pattern) | 需要通过复制现有对象来创建新对象,避免对象的频繁创建和销毁,提高性能和代码复用性。 |
适配器模式 (Adapter Pattern) | 需要将一个类的接口转换为客户端所期望的另一种接口,以适配不兼容的接口,使得原本不兼容的类可以协同工作。 |
装饰器模式 (Decorator Pattern) | 需要动态地为对象添加额外的功能,不改变原始类的结构,而是通过组合的方式扩展对象的功能。 |
外观模式 (Facade Pattern) | 需要为复杂子系统提供一个简化的统一接口,简化客户端与子系统之间的交互,降低耦合度。 |
代理模式 (Proxy Pattern) | 需要通过代理对象控制对另一个对象的访问,可以在访问对象前后增加额外的操作,提供更加灵活和安全的访问方式。 |
桥接模式 (Bridge Pattern) | 需要将抽象部分与其具体实现部分分离,使它们可以独立变化,以提高系统的灵活性和可扩展性。 |
组合模式 (Composite Pattern) | 需要将对象组合成树形结构以表示部分-整体的层次关系,并且希望用户可以以统一的方式处理单个对象和组合对象。 |
享元模式 (Flyweight Pattern) | 需要共享大量细粒度的对象,以减少内存占用和提高性能。 |
观察者模式 (Observer Pattern) | 存在一对多的依赖关系,一个对象的状态变化需要通知其他对象进行相应的更新,实现解耦的事件通知机制。 |
策略模式 (Strategy Pattern) | 需要定义一系列算法,并将其封装成独立的类,使得算法可以相互替换,客户端可以灵活地选择和使用不同的算法实现。 |
命令模式 (Command Pattern) | 需要将请求封装成对象,将发送者和接收者解耦,支持请求的排队、撤销、重做等操作。 |
模板方法模式 (Template Method Pattern) | 需要定义一个算法的骨架,将某些步骤的具体实现延迟到子类中,以便子类可以重新定义某些步骤的具体实现,而不改变算法的结构。 |
状态模式 (State Pattern) | 对象的行为取决于其内部状态,并且需要在运行时根据状态的变化来改变对象的行为,以及简化状态转换逻辑。 |
职责链模式 (Chain of Responsibility Pattern) | 需要将请求的发送者和接收者解耦,使多个对象都有机会处理请求,避免请求发送者和接收者之间的直接耦合,提高系统的灵活性。 |
迭代器模式 (Iterator Pattern) | 需要提供一种统一的方法顺序访问一个聚合对象中的各个元素,而无需暴露其内部表示,以及支持不同的遍历方式。 |
中介者模式 (Mediator Pattern) | 需要通过一个中介对象来封装一系列对象之间的交互,减少对象之间的直接通信,降低耦合度,简化对象之间的关系。 |
访问者模式 (Visitor Pattern) | 需要封装对一个对象结构中各元素的操作,以便在不改变这些元素类的前提下定义新的操作,实现对象结构和操作之间的解耦。 |
解释器模式 (Interpreter Pattern) | 需要定义一种语言的语法表示,并提供解释器来解释这个语法,用于处理特定类型的语法分析和处理。 |
备忘录模式 (Memento Pattern) | 需要在不违背封装原则的前提下,捕获对象的内部状态并在对象之外保存这个状态,以便在之后恢复对象到先前的状态。 |
命名元组模式 (NamedTuple Pattern) | 需要创建具有命名字段的轻量级数据对象,提供了一种方便的方式来定义简单的数据结构。 |
以上是常见的 23 种设计模式及其适用场景。每个模式都有特定的用途和优势,根据不同的需求和情景选择适合的设计模式可以提高代码的可维护性、可扩展性和重用性。
2. Creational
创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离.
Singleton
参考:https://www.jianshu.com/p/83302146a25e
定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式
角色:
- 单例类:包含一个实例且能自行创建这个实例的类。
- 访问类:使用单例的类。
代码实例:
1 | class SingletonMeta(type): |
Prototype
参考:https://www.jianshu.com/p/e20f6ec7beda, https://juejin.cn/post/7000534811697741832
定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象
角色:
抽象原型类:规定了具体原型对象必须实现的接口。
具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
访问类:使用具体原型类中的 clone() 方法来复制新的对象。
当直接创建对象的代价比较大时,则采用这种模式, 原型模式是在内存二进制流的拷贝. 使用场景:
- 通过
new
产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式 - 对象的实例化需要一个高代价的数据库或者其他 IO 操作之后才被创建时, 此时由需要大量创建实例对象, 则可以使用原型
- 原型模式一般和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者
使用实例: JVM 中的 Cloneable 接口, python 中的 copy 拷贝接口都是类似的逻辑, 此时构造函数方法不会执行, 极大的加快了对象的创建速度
对别: 关于原型模式和享元模式的区别见下面的说明.
代码实例:
1 | import copy |
SimpleFactory
参考:https://www.jianshu.com/p/f39f8aea46b3
定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中
角色:
简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。
具体产品(ConcreteProduct):是简单工厂模式的创建目标。
代码实例:
1 | class Animal: |
MethodFactory
参考:https://www.jianshu.com/p/8a4db1229ba2
定义:对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品
角色:
抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
使用或适用场景:
- 凡是使用到 new 或构造函数的地方都可以考虑使用工厂方法模式, 但滥用工厂模式反而加重代码的复杂度
- 不希望子系统(多个)和业务代码大对象进行强耦合, 在运行时可以动态的选择不同的子系统, 那么工厂模式就是一个理想的选择
- 实例的创建需要依赖具体的环境, 并且实例之间的行为大体相同, 此时也可以使用工厂模式
工厂模式是下面很多其他实例的基础, 在正常情况下, 实例的创建不需要基于工厂模式, 例如对于单向关联 A, B 两个实例:
1 | class B: |
此时这种单向关联用法没有任何问题, 即使此时 B 发生大的改动, 联动的到的改动也就是 A 类, 但若是涉及到多个实例关联到 B 类:
1 | class B: |
此时若 B 类发生大的改动, 那么就需要联动更改 A~AN 类, 这明显不符合开闭原则, 所以就产生了工厂模式(其他模式也是类似概念)中间层, 将实例的创建和调用解耦, 减少代码重复, 将所有相同类型实例的创建放在一个单独的 Factory 中, 即使 B 类发生大改动, 此时联动更改仅仅是 Factory(这种说法也有点牵强). 下面是一些工厂模式的使用实例:
- 日志工厂, 根据传入的类型选择不同的日志类型
1 | public class LoggerFactory { |
- 动物
1 | class Animal: |
AbstractFactory
参考:https://www.jianshu.com/p/7eb964c820eb
定义: 是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
角色:
抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
产品等级和产品族:
代码实例:
1 | class Animal: |
Builder
参考:https://www.jianshu.com/p/9d847fd10d24
定义:建造者模式(生成器模式)指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示意图, 此时用户只需要指定需要建造的类型即可, 具体建造的细节和过程对客户透明.
角色:
产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
使用场景:
- 屏幕上画人: 一个人有头, 手, 脚等等, 将一个人的构造拆分为各个部件的构造, 其中指挥者用于控制建造过程,
隔离
用户和建造过程的关联
1 | public class Person { |
构造器参数由非常多(对象有非常复杂的内部结构)的时候, 此时使用静态工厂和构造器都显得太过复杂, 基于
builder
将构造器参数分为几个梯级:- 必须参数
- 可选参数
- 最低优先级参数
在实例化的时候将构造过程拆分为多个梯级或者过程, 其中方法的调用顺序由指挥者来进行控制.
使用建造者模式也可以避免
重叠构造函数的出现
:
1 | class Pizza { |
参考: https://juejin.cn/post/7027810496342392846
代码实例:
1 | class Computer: |
3. Structural
结构性模式(Structural Pattern)描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构
Proxy
参考: https://www.jianshu.com/p/269e48dee73f
定义: 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
角色:
- 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
- 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
- 客户端(Client): 通过代理对象来同真实主题进行交互
积木材料:
- 主题类, Client 可以直接进行访问, 但是通过代理类能够更好的访问主题类
- 代理类, 类似商品交易中的一级代理, 二级代理, 通过代理能够提供更多的功能(卖的更多), 代理自身会在卖出商品前进行人际关系的维护, 线下 PY 交易等等
积木方法: 通过代理的方式完成了以最简单的积木搭建
代码实例:
1 | class Subject: |
Adapter
参考:https://www.jianshu.com/p/0ce7cecf0e68
定义: 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作
角色:
目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
客户端(Client): 客户端直接同 Adapter 进行交互, 不认识 Adaptee 类
类适配器:
对象适配器(适配者以类对象方式存储在适配器中):
积木材料:
- Adaptee: 客户端无法直接访问该类, 亦或者说客户端无法识别 Adaptee 产出的数据格式
- Adapter: 可以封装并产出客户端识别的数据格式
积木方法: 通过 Adapter, 将原本是两个厂生产的积木完美的结合在一起
代码实例:
1 | class OldSystem: |
Bridge
参考: https://www.jianshu.com/p/1111395d28f2
定义: 将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
角色:
- 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
- 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
- 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
- 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
代码实例:
1 | # 实现(Implementor) |
Decorator
参考:https://www.jianshu.com/p/d364f6da5fc5
定义: 装饰器模式指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式
角色:
抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
代码实例:
1 | class Component: |
Facade
参考:https://www.jianshu.com/p/b987b79ae070
定义:外观模式或门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。
角色:
外观(Facade)角色:为多个子系统对外提供一个共同的接口。
子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
客户(Client)角色:通过一个外观角色访问各个子系统的功能。
代码实例:
1 | class SystemA: |
FlyWeight
参考: https://www.jianshu.com/p/162b39f8f520
定义: 运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。
角色:
抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
原型模式和享元模式的区别(https://blog.csdn.net/qq_40378034/article/details/104101065).
代码实例:
1 | import weakref |
Composite
参考:https://www.jianshu.com/p/1a8dbc559758
定义: 组合模式或 part-whole 模式, 它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性
角色:
抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。
代码实例:
1 | from typing import List, Union |
4. Behavioral
行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化, 其关注职责的分配
Template
参考:https://www.jianshu.com/p/e95e55efcabe
定义: 模板方法定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
角色:
1. Abstract Class负责给出一个算法的轮廓和骨架
+ 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法
+ 基本方法:是整个算法中的一个步骤(抽象方法, 具体方法, 钩子方法)
2. Concrete Class实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。
代码实例:
1 | from abc import ABC, abstractmethod |
Strategy
参考:https://www.jianshu.com/p/ffabe88100a1
定义: 策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。
角色:
抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
环境(Context)类:持有一个策略类的引用,最终给客户端调用。
代码实例:
1 | from abc import ABC, abstractmethod |
Command
参考: https://www.jianshu.com/p/079268e8e5da
定义: 命令模式将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。
角色:
抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。
具体命令类(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。
代码实例:
1 | class Command(ABC): |
ChainOfRes
参考: https://www.jianshu.com/p/c256a84ef27a
定义: 责任链为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
角色:
抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
代码实例:
1 | class Handler(ABC): |
State
参考:https://www.jianshu.com/p/5ad821766ddc
定义: 状态模式对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
角色:
- 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
- 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
- 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
代码实例:
1 | class State(ABC): |
Observer
参考: https://www.jianshu.com/p/ad8e400ea3f3
定义: 观察者(发布订阅, 模型视图)指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
角色:
抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
代码实例:
1 | # 观察者模式 |
Mediator
参考: https://www.jianshu.com/p/b799395466b8
定义: 中介者(调停模式)定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互. 它是迪米特法则的典型应用.
角色:
- 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
- 具体中介者(Concrete Mediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
- 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
- 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。
代码实例:
1 | # 中介者模式 |
Iterator
参考:https://www.jianshu.com/p/c8b458efb138
定义: 迭代器提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示
角色:
抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
代码实例:
1 | # 迭代器模式 |
Visitor
参考:https://www.jianshu.com/p/927582f7b394
定义: 访问者将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。
角色:
抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
代码实例:
1 | # 访问者模式 |
Memento
参考: https://www.jianshu.com/p/f0236f5b60f1
定义: 备忘录模式在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式
使用场景: 撤销和恢复操作, 数据库的回滚操作, 中间结果存档功能, 数据备份功能, 棋类游戏中的悔棋操作等
角色:
发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
代码实例:
1 | # 备忘录模式 |
Interpreter
参考: https://www.jianshu.com/p/805c9ca1043e
定义: 解释器给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子
角色:
抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
代码实例:
1 |