type
status
date
slug
summary
tags
category
icon
password
fullWidth
fullWidth
23种设计模式
【创建型】单例模式
概念
- 定义:单例模式是一种创建型设计模式,目的是确保一个类只有一个实例,并提供一个全局访问点;在游戏开发中,单例模式常用于管理全局数据、游戏状态或者资源管理
- 实现:单例模式有两种实现方式:饿加载(Eager Initialization)和懒加载(Lazy Initialization);区别在于实例化对象的时机
- 饿加载:在类加载时就创建单例实例
- 优点:实现简单,线程安全
- 缺点:如果单例实例比较大且不一定会用到会浪费内存
- 懒加载:在第一次需要使用时才创建单例实例
- 优点:节省资源,只有在需要时才创建实例
- 缺点:需要处理线程安全问题;加上线程锁每次调用时的同步检测影响性能
实例
- 饿加载:在类声明时就实例化
- 懒加载(不加线程锁):在多线程环境下是不安全的,因为多个线程可能同时进入GetInstance()方法并通过if (instance == null)检查;这会导致多个线程同时创建多个实例
- 假设两个线程A和B同时调用getInstance()方法
- 线程A检查instance是否为null,发现是null
- 线程B也检查instance是否为null,也发现是null
- 线程A创建一个新的Singleton实例并赋值给instance
- 线程B也创建一个新的Singleton实例并赋值给instance
- 最终会有两个Singleton实例存在,违反了单例模式的原则
- 懒加载(加线程锁):通过在GetInstance()方法上使用synchronized关键字,确保了在多线程环境下只有一个线程能够进入该方法并创建实例,从而避免了多个线程同时创建多个实例的问题
- 使用synchronized关键字会导致每次调用getInstance()方法时都进行同步检查,可能会影响性能
- 懒加载(双重校验锁):第一次检查instance是否为null时不进行同步,只有在instance为null时才进行同步检查,从而减少了不必要的同步开销,同时保证了线程安全
Volatile关键字:用于确保变量的可见性和防止指令重排序
当一个线程修改了volatile修饰的变量的值,新的值会立即被刷新到主内存中,其他线程读取该变量时会得到最新的值
此外,还防止编译器和CPU对变量的读写操作进行重排序;在写入volatile变量之前的所有操作都不会被重排序到写入之后,从而确保变量在被其他线程访问之前已经初始化
lock关键字:lock关键字用于确保一段代码在同一时间只能被一个线程执行;当一个线程进入lock块时,其他试图进入该块的线程会被阻塞,直到当前线程退出lock块
- 懒加载(C#独有的):在C#中,Lazy<T>类提供了一种线程安全的懒加载机制,并从内部实现了线程安全
【创建型】三种工厂模式
- 工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的接口,而不是通过具体类来实例化对象;工厂模式可以将对象的创建过程封装起来,使代码更具有灵活性和可扩展性。
- 三种工厂模式适用于不同的场景:当对象的创建逻辑简单且不需要大量的子类时,工厂模式是一个不错的选择;当系统需要通过引入新的子类来扩展对象的创建过程时,工厂方法模式非常适用;当需要创建一组相关或相互依赖的对象时,抽象工厂模式是一个理想的选择。
简单工厂模式
概念
- 简单工厂模式(Simple Factory Pattern): 通过一个工厂类来决定创建哪种具体类的实例;这个工厂类通常是静态类,提供一个静态方法,根据传入的参数创建相应的对象。
- 构成
- 产品接口(Product Interface):包含产品的生产的行为。
- 具体产品类(Concrete Product Class):实现产品类接口,具体产品对象。
- 工厂类(Factory Class):用于生成不同产品对象。
实例
- 产品接口
- 具体产品类
- 静态工厂类
- 使用示例
工厂方法模式
概念
- 工厂方法模式(Factory Method Pattern):定义了一个创建对象的接口,但由子类决定实例化哪一个类。工厂方法模式使得一个类的实例化延迟到其子类。
- 构成
- 产品接口(Product Interface):定义产品的接口。
- 具体产品类(Concrete Product Class):实现产品接口的具体类。
- 工厂接口(Factory Interface):定义创建产品对象的接口。
- 具体工厂类(Concrete Factory Class):实现工厂接口的具体类。
实例
- 产品接口
- 具体产品类
- 工厂接口
- 具体工厂类
- 使用示例
抽象工厂模式
概念
- 抽象工厂模式(Abstract Factory Pattern): 提供一个接口,用于创建相关或依赖对象的家族,而无需明确指定具体类。通过使用抽象工厂模式,一个类可以实例化一组相关对象,而不需要知道它们的具体类。
- 构成
- 抽象产品接口(Abstract Product Interface):为每种产品声明一个接口。
- 具体产品(Concrete Product):实现抽象产品接口的具体类。
- 抽象工厂接口(Abstract Factory Interface):声明了一组用于创建一族产品的方法。
- 具体工厂(Concrete Factory):实现抽象工厂的接口,负责创建具体产品对象。
实例
- 产品接口
- 具体产品
- 工厂接口
- 具体工厂
- 使用示例
- UML类图

【创建型】原型模式
概念
- 原型(Prototype)设计模式是一种创建型设计模式,通过复制现有对象来创建新对象,而不是通过类构造函数实例化对象。
- 设计意图:
- 避免重复的初始化代码。
- 提高对象创建的效率。
- 使用场景
- 当一个系统应该独立于其产品创建、构成和表示。
- 当要实例化的类是在运行时动态创建。
- 为了避免创建一个与产品类层次平行的工厂类层次。
- 当一个类的实例只能有几个不同状态组合中的一种。
- 构成
- Prototype(原型接口):声明一个克隆自身的接口。
- ConcretePrototype(具体原型类):实现一个克隆自身的操作。
- 优点
- 性能提升:通过克隆对象来创建新对象,比通过构造函数创建对象更高效。
- 简化对象创建:避免了复杂的初始化过程。
- 动态扩展:可以在运行时动态地增加对象。
- 缺点
- 需要区分浅拷贝和深拷贝:对于引用类型的字段,需要实现深拷贝。
- 克隆方法的实现:每个类都需要实现克隆方法,增加了代码复杂性。
实例
- 原型接口
浅拷贝:会复制对象的所有字段,但对于引用类型字段只复制引用,而不复制引用的对象本身;在C#中,可以使用 MemberwiseClone 方法实现浅拷贝。
深拷贝:不仅复制对象的所有字段,还会递归地复制引用类型字段所引用的对象,确保新对象完全独立于原始对象。
- IdInfo类;其类对象作为ConcretePrototype类中引用类型的变量
- 具体原型类
- 实例
- 打印结果
【创建型】建造者模式
概念
- 建造者模式:将一个复杂对象的构建过程分解为多个简单的步骤,使得构建过程可以一步步进行,并且可以灵活地创建不同的表示。
- 设计意图:将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。它主要用于创建一些复杂的对象,这些对象由多个部分组成。
- 使用场景
- 需要生成的对象具有复杂的内部结构。
- 需要生成的对象的内部属性相互依赖。
- 希望通过不同的组合来创建不同的对象。
- 构成
- Builder(建造者):定义创建产品各个部分的接口。
- ConcreteBuilder(具体建造者):实现Builder接口,构建和装配各个部分。
- Director(指挥者):构建一个使用Builder接口的对象。
- Product(产品):表示被构建的复杂对象。
- 优点
- 更好的控制对象的创建过程:可以一步步地创建对象,并且可以灵活地创建不同的表示。
- 代码更具可读性和可维护性:将复杂对象的创建过程分解为多个简单的步骤。
- 符合单一职责原则:将对象的创建过程与其表示分离。
- 缺点
- 增加了代码的复杂性:需要定义多个Builder类和Director类。
- 不适合变化多的产品:如果产品的内部结构经常变化,可能需要频繁修改Builder类。

实例
- 抽象建造者
- 具体建造者
- 指挥者
- 产品类
- 客户端代码
- 打印结果
【结构型】外观模式
概念
- 定义:外观模式(Facade Pattern)是一种结构型设计模式,它为子系统的一组接口提供一个一致的界面(即定义一个高层接口),从而简化客户端对这些子系统的使用
- 结构:外观模式通常包含以下几部分
- 外观类(Facade):提供一个高层接口,使得子系统更容易使用
- 子系统类(Subsystem Classes):实现子系统的功能,外观类会调用这些类来完成实际的工作
- 优点
- 简化接口:通过提供一个简单的接口,减少了客户端与子系统之间的耦合
- 提高灵活性:子系统的变化不会影响到客户端,只需修改外观类即可
- 更好的分层:有助于将复杂系统分层,使得每一层只关注自己的职责
- 缺点
- 外观模式在增加新的子系统功能时,可能需要修改外观类,这违背了开闭原则
- 当子系统非常复杂且分散,或子系统之间交互方式频繁变化,外观模式可能会导致外观类变得庞大臃肿
实例
- 现有三个子系统
- 不使用外观模式
- 使用外观模式
【结构型】组合模式
概念
- 组合模式(Composite Pattern):一种结构型设计模式,它允许将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。
- 设计意图:
- 客户端可以一致地处理单个对象和组合对象。
- 通过递归组合的方式来构建复杂的对象结构。
- 组合模式适用于以下场景:
- 需要表示对象的“部分-整体”层次结构时,例如文件系统、组织结构、UI组件树等。
- 希望客户端可以忽略组合对象与单个对象的差异,统一地使用组合结构中的所有对象时。
- 组合模式主要包含以下角色:
- Component(组件):定义组合对象和叶子对象的接口。
- Leaf(叶子):表示组合中的叶子对象,没有子对象。
- Composite(组合):表示有子对象的组合对象,定义子对象的管理方法。

- 优点:
- 简化客户端代码,使得客户端可以一致地处理组合对象和单个对象。
- 更容易添加新的类型的组件。
- 缺点:
- 使得设计变得更加复杂,特别是在需要管理大量对象时。
- 可能会导致系统中的对象数量增加。
实例
- 抽象类:Component
- 叶子类:Leaf
- 组合类:Composite
- 实例:
- 打印结果

【结构型】代理模式
概念
- 代理模式(Proxy Pattern)是一种结构型设计模式,它通过代理对象控制对原对象的访问。代理模式可以为对象的访问提供额外的功能,例如控制访问权限、延迟加载、日志记录等。
- 设计意图:代理模式的设计意图是为对象提供一个代理,以便在不改变对象接口的情况下,控制对对象的访问。代理模式可以用于以下几种情况:
- 远程代理:为一个对象在不同地址空间提供局部代表。
- 虚拟代理:根据需要创建开销很大的对象。
- 保护代理:控制对原始对象的访问。
- 智能引用代理:在访问对象时执行一些附加操作。
- 代理模式主要由以下几个部分构成:
- 接口(Subject):定义了代理类和真实类的公共接口。
- 真实类(RealSubject):实现了接口的类,是真正需要被代理的对象。
- 代理类(Proxy):实现了接口,并持有真实类的引用,控制对真实类的访问。
- 优点
- 控制访问:可以控制对真实对象的访问,增加安全性。
- 延迟加载:可以延迟加载开销大的对象,提升性能。
- 附加功能:可以在访问对象时添加额外的功能,如日志记录、性能监控等。
- 缺点
- 增加复杂性:引入代理对象会增加系统的复杂性。
- 性能开销:代理模式会增加一些额外的性能开销,特别是在频繁访问的场景下。
实例
- 定义银行账户接口,代理类和真实类的公共接口
- 定义银行账户,真实类
- 定义代理类
- 使用
- 打印结果
【结构型】适配器模式
概念
- 适配器模式(Adapter Pattern):是一种结构型设计模式,它的主要目的是将一个类的接口转换成客户端希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以协同工作。适配器模式有两种实现方式:对象适配器和类适配器。
- 对象适配器:通过继承的方式,将适配器类与被适配的对象关联起来。
- 类适配器:通过组合的方式,将适配器类与被适配的类关联起来。


- 构成
- 目标接口(Target):定义客户端所需的接口。
- 适配者(Adaptee):定义一个已经存在的接口,这个接口需要适配。
- 适配器(Adapter):实现目标接口,并通过组合或继承的方式调用适配者的接口。
- 优点
- 可以让任何两个没有关联的类一起运行。
- 提高了类的复用性。
- 增加了类的透明性和灵活性。
- 缺点
- 过多地使用适配器会让系统变得复杂。
- 由于引入了额外的适配器层,可能会影响性能。
- 在游戏开发中的应用
- 数据库访问:不同的数据库(如MySQL、MongoDB)有不同的访问接口。适配器模式可以将这些不同的接口统一成一个标准接口,简化数据库操作。
- 第三方库集成:游戏开发中经常需要使用第三方库(如物理引擎、图形库)。适配器模式可以将这些库的接口转换为游戏引擎所需的接口,简化集成过程。
- 旧代码复用:在游戏开发中,可能需要复用旧项目中的代码。适配器模式可以将旧代码的接口适配到新项目中使用,避免重写代码。
实例
- 目标接口
- 被适配者
对象适配器
- 适配器
- 客户端
类适配器
- 适配器
- 客户端
【结构型】桥接模式
定义
- 桥接模式(Bridge Pattern)是一种结构型设计模式,旨在将抽象部分与其实现部分分离,使它们可以独立地变化;它通过组合而不是继承来实现这种分离。
- 桥接模式的设计意图是:
- 解耦抽象和实现:使得抽象和实现可以独立变化,不会相互影响。
- 提高系统的扩展性:通过分离抽象和实现,可以更容易地扩展系统的功能。
- 桥接模式适用于以下场景:
- 当一个系统需要在多个维度上扩展时,例如形状和颜色的组合。
- 当不希望在抽象类和实现类之间建立紧密耦合时。
- 当系统希望避免由于增加实现类数量而导致的类的爆炸性增加时。
- 桥接模式主要涉及以下几个组成部分:
- 实现类接口(Implementor):定义实现类的接口,提供具体的实现。
- 具体实现类(ConcreteImplementor):实现实现类接口,提供具体的实现方式。
- 抽象类(Abstraction):定义了使用实现类接口的接口。
- 扩展抽象类(RefinedAbstraction):实现抽象类所定义的接口,可能增加一些额外的方法。
- 优点
- 提高系统的扩展性:抽象和实现可以独立扩展。
- 减少类的数量:通过组合而不是继承来减少类的数量。
- 缺点:
- 增加系统的复杂性:由于引入了额外的抽象层,系统的复杂性可能会增加。

实例
- 实现类接口
- 具体实现类
- 抽象类
- 扩展抽象类
- 客户端代码
【结构型】享元模式
概念
- 定义:享元模式是一种结构型设计模式,主要用于减少创建对象的数量,以减少内存占用和提高性能。它通过共享多个对象的部分状态来实现。
- 享元模式适用于以下场景:
- 系统中有大量相似对象,这些对象会占用大量内存。
- 对象的大部分状态可以被外部化或共享。
- 需要通过共享来降低内存占用,如数据库连接池、字符串缓存池等。
- 享元模式主要由以下角色组成:
- 抽象享元角色(Flyweight):通常是一个接口或抽象类,声明了具体享元类公共的方法。
- 享元工厂角色(Flyweight Factory):负责创建和管理享元对象。
- 具体享元角色(Concrete Flyweight):实现了抽象享元类,在该类中为内部状态提供了存储空间。
- 非共享享元角色(Unsharable Flyweight):不能被共享的子类。
- 优点:
- 减少内存消耗:通过共享对象,降低了系统中对象的数量,从而减少内存占用。
- 使用了相对独立的外部状态:不会影响内部状态,能使得享元对象在不同环境中被共享。
- 缺点:
- 享元模式需要区分外部状态和内部状态,使得应用程序某种程度上复杂化了。
- 为了使对象可以共享,需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
暂时无法在飞书文档外展示此内容
实例
- 抽象享元接口:
- 具体享元类(可共享):
- 具体享元类(非共享):
- 享元工厂类:
- 客户端代码
- 打印结果
【结构型】装饰模式
概念
- 装饰模式(Decorator Pattern)是一种结构型设计模式,可以动态地给对象添加新的行为,无需修改其代码。
- 实现:装饰模式通过创建一个装饰类来包装原始类,从而在不改变原始类的情况下扩展其功能。装饰类和原始类具有相同的接口,这样客户端就可以透明地使用装饰类。
- 装饰模式的设计意图:
- 动态地给对象添加职责。
- 通过使用多个不同的装饰类,可以在运行时组合出各种不同的行为。
- 装饰模式由以下几个部分构成:
- 组件接口(Component):定义对象的接口,可以是抽象类或接口。
- 具体组件(ConcreteComponent):实现组件接口的类,表示被装饰的原始对象。
- 装饰器(Decorator):实现组件接口的抽象类,包含一个指向组件对象的引用。
- 具体装饰器(ConcreteDecorator):继承装饰器类,向组件添加新的行为。
- 装饰模式适用于以下场景:
- 需要在不修改原始类代码的情况下扩展类的功能。
- 需要动态地添加或撤销对象的职责。
- 需要通过组合不同的装饰类来实现复杂的功能。
- 优点
- 灵活性高:可以动态地添加或撤销对象的职责。
- 遵循开闭原则:可以在不修改原始类的情况下扩展其功能。
- 组合性强:可以通过组合多个装饰类来实现复杂的功能。
- 缺点
- 增加复杂性:由于使用了多个小对象,系统可能会变得复杂。
- 调试困难:由于装饰器的嵌套,调试时可能难以追踪对象的行为。

实例
- 组件接口
- 具体组件
- 装饰器抽象类,继承组件接口并持有组件成员变量
- 具体装饰器
- 客户端代码
- 打印结果
【行为型】中介者模式
概念
- 定义:中介者模式是一种行为型设计模式,主要用于降低多个对象和类之间的通信复杂性;中介者模式定义了一个中介对象来封装一系列对象之间的交互;使各对象之间不需要显式地相互引用,从而使其耦合松散,且可以独立地改变它们之间的交互
- 作用:解决对象间复杂的一对多关联问题,避免对象之间的高度耦合,简化系统结构
- 实现方式:
- 定义中介者接口:规定中介者必须实现的接口
- 创建具体中介者:实现中介者接口,包含协调各同事对象交互的逻辑
- 定义同事类:各个对象不需要显式地相互引用,而是通过中介者来进行交互
- 优点:
- 降低复杂度:将多个对象间的一对多关系转换为一对一关系
- 解耦:对象之间不再直接引用,通过中介者进行交互
- 符合迪米特原则:对象只需知道中介者,不需要知道其他对象
- 缺点:
- 中介者复杂性:中介者可能会变得庞大和复杂,难以维护
实例
中介者模式包含以下几个主要角色:
- 中介者(IMediator):定义了一个接口用于与各个同事对象通信,并管理各个同事对象之间的关系;通常包括一个或多个事件处理方法,用于处理各种交互事件
- 具体中介者(Concrete Mediator):实现了中介者接口,负责实现各个同事对象之间的通信逻辑;维护一个对各个同事对象的引用,并协调它们的交互
- 同事对象(Colleague):定义了一个接口或抽象类,用于与中介者进行通信;通常包括一个发送消息的方法,以及一个接收消息的方法
- 具体同事对象(Concrete Colleague):实现了同事对象接口,是真正参与到交互中的对象。它会将自己的消息发送给中介者,由中介者转发给其他同事对象
【行为型】观察者模式
概念
- 定义:观察者模式是一种行为型模式,创建了对象间的一对多的依赖关系,当一个对象状态改变时,所有依赖于它的对象都会得到通知并自动更新
- 结构:观察者模式包含以下几个核心角色
- 主题(Subject):也称为被观察者,它是有状态的对象,并维护着一个观察者列表;主题提供了添加、删除和通知观察者的方法
- 观察者(Observer):观察者是接收主题通知的对象;观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作
- 具体主题(Concrete Subject):具体主题是主题的具体实现类;它维护着观察者列表,并在状态发生改变时通知观察者
- 具体观察者(Concrete Observer):具体观察者是观察者的具体实现类;它实现了更新方法,定义了在收到主题通知时需要执行的具体操作
- 实现方式
- 定义观察者接口:包含一个更新方法
- 创建具体观察者:实现观察者接口,定义接收到通知时的行为
- 定义主题接口:包含添加、删除和通知观察者的方法
- 创建具体主题:实现主题接口,管理观察者列表,并在状态改变时通知它们
- 优点
- 抽象耦合:观察者和主题之间是抽象耦合的
- 触发机制:建立了一套状态改变时的触发和通知机制
- 缺点
- 性能问题:如果观察者众多,通知过程可能耗时
- 循环依赖:观察者和主题互相依赖,可能导致循环调用
实例
- 观察者接口
- 观察者类
- 主题接口
- 主题类
- 使用实例
- 打印结果
【行为型】责任链模式
概念
- 定义:责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许将请求沿着处理者链传递,直到有一个处理者处理它;可以避免请求的发送者与接收者之间的紧耦合关系
- 结构:
- Handler(处理者):定义一个处理请求的接口,并且可以选择设置下一个处理者
- ConcreteHandler(具体处理者):实现处理请求的接口,如不能处理请求,则将其传递给下一个处理者
- Client(客户端):向链中的第一个处理者发送请求
- 优点
- 降低耦合度:请求发送者和接收者解耦,发送者不需要知道具体哪个对象处理请求,只需将请求传递给链中的第一个处理者
- 增强系统可扩展性:可以根据需要增加新的请求处理类,符合开闭原则
- 职责分担:每个处理者只需处理自己负责的部分,其他部分传递给下一个处理者,符合单一职责原则
- 灵活性高:可以动态地改变链内的成员或调整它们的顺序,可以动态地新增或删除处理者
- 缺点
- 性能问题:如果责任链过长,或者链中的处理者处理时间过长,可能会影响性能
- 调试困难:请求在链中传递时,可能很难跟踪和调试,特别是在链条较长且处理逻辑复杂的情况下
实例
- 抽象处理者
- 名字
- 下一个处理者的引用
- 设置下一个处理者的方法
- 处理请求的抽象方法
- 通用处理者:继承抽象处理者,提供设置处理范围的接口,重写处理请求的方法
- 具体处理者
- 返回值
【行为型】备忘录模式
概念
- 备忘录模式(Memento Pattern)是一种行为型设计模式,它允许在不破坏封装性的前提下捕获和恢复对象的内部状态;这个模式特别适用于需要撤销操作的场景,比如文本编辑器、游戏存档等。
- 作用:
- 保存对象状态:在某个时刻保存对象的状态,以便在需要时恢复。
- 实现撤销操作:允许用户撤销操作,恢复到之前的状态。
- 防止状态破坏:通过封装,防止外部对象破坏对象的内部状态。
- 结构:备忘录模式包含三个角色
- 发起人(Originator):负责创建一个包含其当前内部状态的备忘录,并使用备忘录恢复其内部状态。
- 备忘录(Memento):存储发起人的内部状态。
- 管理者(Caretaker):负责保存备忘录,但不能对备忘录的内容进行操作或检查。
- 优点
- 封装性:保持对象的封装性,防止外部对象破坏其内部状态。
- 简化撤销操作:通过保存状态,简化了撤销操作的实现。
- 缺点
- 资源消耗:保存对象的状态可能会消耗大量内存,特别是当对象的状态非常复杂时。
- 实现复杂:需要额外的类和管理逻辑来保存和恢复状态。
实例
- 定义状态(State)结构体
- 定义发起人(Originator)类,需要有保存状态和恢复状态的方法
- 定义备忘录(Memento)类,其中有State类型的成员变量用于保存状态
- 定义管理者类(CareTaker)
- 应用
- 输出结果
【行为型】状态模式
概念
- 状态模式(State Pattern):是一种行为设计模式,它允许对象在其内部状态改变时改变其行为。状态模式将与状态相关的行为抽取到独立的状态类中,使得原对象将工作委派给这些状态类的实例,而不是自行处理。这样可以避免大量的条件语句,提高代码的可维护性和扩展性。状态模式在游戏开发中有广泛的应用,比如处理角色状态、AI行为、游戏场景切换等。
- 组成:
- State(状态):定义一个接口,用以封装与上下文的一个特定状态相关的行为。
- ConcreteState(具体状态):实现状态接口的具体状态类。
- Context(上下文):维护一个状态实例,这个实例定义了当前的状态。

- 优点
- 简化复杂状态转换逻辑:状态模式将与状态相关的行为分散到独立的状态类中,避免了在上下文类中使用大量的条件语句,从而简化了代码结构。
- 提高可维护性和可扩展性:新的状态和状态转换可以通过添加新的状态类来实现,而不需要修改现有的代码,符合开闭原则。
- 状态切换更清晰:状态模式使得状态切换更加明确和直观,每个状态类只负责处理其特定的行为和状态转换。
- 封装状态:状态模式将状态和行为封装在独立的类中,使得状态的变化对其他类透明,减少了耦合。
- 缺点
- 类的数量增加:状态模式需要为每个具体状态创建一个类,可能会导致类的数量增加,增加系统的复杂性。
- 状态之间的依赖:如果状态之间存在复杂的依赖关系,可能会导致状态类之间的耦合增加。
- 状态切换的开销:状态切换可能会引入额外的开销,特别是在状态切换频繁的情况下。
实例
- 状态接口
- 具体状态:继承状态接口并实现其中处理状态的方法
- 上下文类
- 应用
【行为型】命令模式
概念
- 命令模式(Command Pattern)是一种行为设计模式,它将请求封装成对象,从而使用户可以用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
- 应用场景:
- 需要参数化对象的操作:例如,菜单项的点击操作。
- 需要将操作放入队列中执行:例如,任务调度系统。
- 需要支持撤销操作:例如,文本编辑器中的撤销和重做功能。
- 构成:
- 命令接口(Command):声明执行操作的接口。
- 接收者(Receiver):执行命令相关的操作。
- 具体命令类(ConcreteCommand):持有接收者,实现命令接口,定义具体的操作。
- 调用者(Invoker):持有命令对象,并在某个时间点调用命令对象的执行方法。

实例
- 命令接口(Command)
- 接收者(Receiver)
- 具体命令类(ConcreteCommand)
- 调用者(Invoker)
- 客户端
【行为型】访问者模式
概念
- 定义:访问者模式(Visitor Pattern)是一种行为设计模式,它能将算法与对象结构分离,使得新的操作可以在不改变对象结构的情况下被添加。
- 设计意图:将数据结构与作用于数据结构的操作分离。这样可以在不改变数据结构的前提下,增加新的操作。
- 访问者模式适用于以下场景:
- 对象结构相对稳定,但经常需要在此结构上定义新的操作。
- 需要对一个对象结构中的对象进行很多不同且不相关的操作,但不希望这些操作“污染”对象的类。
- 对象结构包含许多类,这些类有不同的接口,需要对这些类执行一些依赖于具体类的操作。
- 访问者模式主要由以下几个部分构成:
- Visitor(访问者):为对象结构中的每一个具体元素类声明一个访问操作接口。
- ConcreteVisitor(具体访问者):实现每个访问操作,定义对每个具体元素的操作。
- Element(元素):定义一个接受访问者的方法,该方法通常称为 Accept。
- ConcreteElement(具体元素):实现 Accept 方法,该方法调用访问者的相应方法。
- ObjectStructure(对象结构):能够枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素。
- 优点:
- 增加新的操作很容易:可以在不改变对象结构的情况下增加新的操作。
- 符合单一职责原则:将不相关的行为分离到不同的类中。
- 符合开闭原则:可以在不修改现有代码的情况下增加新的功能。
- 缺点:
- 难以增加新的元素:如果需要在对象结构中增加新的元素,所有的访问者都需要修改。
- 破坏封装:访问者模式要求访问者对象访问并操作对象结构中的数据,这可能会破坏对象的封装性。
- 复杂性:对于简单的对象结构,使用访问者模式可能会增加不必要的复杂性。

实例
- 访问者接口,使用函数重载实现访问不同的元素
- 具体访问者,实现接口方法
- 元素接口
- 具体元素
- 对象结构
- 客户端代码
- 打印结果
【行为型】策略模式
概念
- 定义:策略模式是一种行为设计模式,它允许在运行时选择算法的行为。通过将算法封装在独立的策略类中,可以在不修改客户端代码的情况下更改算法。
- 设计意图:策略模式的设计意图是将算法的定义与使用算法的客户类分离开来,使得算法独立于客户类变化。这有助于提高代码的灵活性和可维护性。
- 策略模式适用于以下场景:
- 当一个类的行为或其算法可以在运行时更改时。
- 当系统中存在大量类似的类,而它们之间的区别仅在于它们的行为时。
- 需要避免使用多重条件选择语句(如if-else或switch-case)来决定使用哪种算法时。
- 策略模式主要由以下几个部分构成:
- 策略接口(Strategy):定义所有支持的算法的通用接口。
- 具体策略类(ConcreteStrategy):实现策略接口,提供具体的算法实现。
- 上下文类(Context):持有一个策略接口的引用,并在运行时调用具体策略类的方法。
- 优点
- 算法可以自由切换:由于策略类都实现了相同的接口,所以它们之间可以自由切换。
- 易于扩展:增加一个新的策略只需要添加一个具体的策略类即可,基本不需要修改原有代码。
- 避免使用多重条件选择语句:充分体现了面向对象设计思想。

实例
- 策略接口
- 具体策略:加法和减法
- 上下文类
- 客户端
【行为型】解释器模式
概念
- 解释器模式(Interpreter Pattern)是一种行为设计模式,主要用于定义一种语言的文法表示,它将一种表达式的语义进行抽象和封装,并建立一个解释器来解释该语言中的句子。
- 使用场景
- 需要解释执行一个特定的语言或语法规则时。
- 需要实现一个可定制的、可扩展的语法解析器时,如配置文件的解析、SQL查询的解析等。
- 需要实现一个可动态改变解析规则的系统时,如脚本引擎、模板引擎等。
- 解释器模式包含以下几个组成部分:
- 抽象表达式(Abstract Expression):定义解释器的接口,约定解释操作。
- 终结符表达式(Terminal Expression):实现与文法中的终结符相关的解释操作。
- 非终结符表达式(Nonterminal Expression):实现与文法中的非终结符相关的解释操作。
- 环境(Context):包含解释器需要的全局信息。
- 客户端(Client):构建抽象语法树,并调用解释操作。
- 优点
- 扩展性好:可以通过继承等机制来改变或扩展文法。
- 容易实现:在语法树中的每个表达式节点类都是相似的。
- 缺点
- 执行效率较低:通常使用大量的循环和递归调用,当要解释的句子较复杂时,运行速度较慢。
- 类膨胀:每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加。
- 应用场景少:需要定义语言文法的应用实例非常少。

实例
- 抽象表达类
- 终结符表达式
- 非终结符表达式
- 客户端
【行为型】模板方法模式
概念
- 模板方法模式:定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
- 设计意图:通过把不变的行为搬移到超类,去除子类中的重复代码。它提供了一种代码复用的有效方式。
- 使用场景
- 多个子类有共有的方法,并且逻辑基本相同时。
- 重要的、复杂的方法,可以考虑作为模板方法。
- 重构时,模板方法模式是一个经常使用的模式。
- 构成
- 抽象类(AbstractClass):定义模板方法和基本方法。模板方法定义了算法的骨架,而基本方法是算法的组成部分。
- 具体类(ConcreteClass):实现抽象类中的基本方法。
- 优点
- 提高代码复用性:将相同部分的代码放在抽象的父类中,而将不同的代码放在不同的子类中。
- 提高扩展性:增加新的行为时,只需要新增一个子类即可。
- 符合开闭原则:通过增加子类来实现扩展,而不是修改已有的代码。
- 缺点
- 类数量增加:每一个抽象类都需要一个具体类来实现,导致类的数量增加。
- 类间关系复杂:增加了类间的耦合。

实例
- 抽象类
- 具体类
- 客户端
- 打印结果
- Author:Yuki
- URL:http://shirakoko.xyz/article/design-pattern
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts