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类图
notion image

【创建型】原型模式

概念

  • 原型(Prototype)设计模式是一种创建型设计模式,通过复制现有对象来创建新对象,而不是通过类构造函数实例化对象。
  • 设计意图:
    • 避免重复的初始化代码。
    • 提高对象创建的效率。
  • 使用场景
    • 当一个系统应该独立于其产品创建、构成和表示。
    • 当要实例化的类是在运行时动态创建。
    • 为了避免创建一个与产品类层次平行的工厂类层次。
    • 当一个类的实例只能有几个不同状态组合中的一种。
  • 构成
    • Prototype(原型接口):声明一个克隆自身的接口。
    • ConcretePrototype(具体原型类):实现一个克隆自身的操作。
  • 优点
    • 性能提升:通过克隆对象来创建新对象,比通过构造函数创建对象更高效。
    • 简化对象创建:避免了复杂的初始化过程。
    • 动态扩展:可以在运行时动态地增加对象。
  • 缺点
    • 需要区分浅拷贝和深拷贝:对于引用类型的字段,需要实现深拷贝。
    • 克隆方法的实现:每个类都需要实现克隆方法,增加了代码复杂性。

实例

  • 原型接口
💡
浅拷贝:会复制对象的所有字段,但对于引用类型字段只复制引用,而不复制引用的对象本身;在C#中,可以使用 MemberwiseClone 方法实现浅拷贝。
深拷贝:不仅复制对象的所有字段,还会递归地复制引用类型字段所引用的对象,确保新对象完全独立于原始对象。
  • IdInfo类;其类对象作为ConcretePrototype类中引用类型的变量
  • 具体原型类
  • 实例
  • 打印结果

【创建型】建造者模式

概念

  • 建造者模式:将一个复杂对象的构建过程分解为多个简单的步骤,使得构建过程可以一步步进行,并且可以灵活地创建不同的表示。
  • 设计意图:将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。它主要用于创建一些复杂的对象,这些对象由多个部分组成。
  • 使用场景
    • 需要生成的对象具有复杂的内部结构。
    • 需要生成的对象的内部属性相互依赖。
    • 希望通过不同的组合来创建不同的对象。
  • 构成
    • Builder(建造者):定义创建产品各个部分的接口。
    • ConcreteBuilder(具体建造者):实现Builder接口,构建和装配各个部分。
    • Director(指挥者):构建一个使用Builder接口的对象。
    • Product(产品):表示被构建的复杂对象。
  • 优点
    • 更好的控制对象的创建过程:可以一步步地创建对象,并且可以灵活地创建不同的表示。
    • 代码更具可读性和可维护性:将复杂对象的创建过程分解为多个简单的步骤。
    • 符合单一职责原则:将对象的创建过程与其表示分离。
  • 缺点
    • 增加了代码的复杂性:需要定义多个Builder类和Director类。
    • 不适合变化多的产品:如果产品的内部结构经常变化,可能需要频繁修改Builder类。
notion image

实例

  • 抽象建造者
  • 具体建造者
  • 指挥者
  • 产品类
  • 客户端代码
  • 打印结果

【结构型】外观模式

概念

  • 定义:外观模式(Facade Pattern)是一种结构型设计模式,它为子系统的一组接口提供一个一致的界面(即定义一个高层接口),从而简化客户端对这些子系统的使用
  • 结构:外观模式通常包含以下几部分
    • 外观类(Facade):提供一个高层接口,使得子系统更容易使用
    • 子系统类(Subsystem Classes):实现子系统的功能,外观类会调用这些类来完成实际的工作
  • 优点
    • 简化接口:通过提供一个简单的接口,减少了客户端与子系统之间的耦合
    • 提高灵活性:子系统的变化不会影响到客户端,只需修改外观类即可
    • 更好的分层:有助于将复杂系统分层,使得每一层只关注自己的职责
  • 缺点
    • 外观模式在增加新的子系统功能时,可能需要修改外观类,这违背了开闭原则
    • 当子系统非常复杂且分散,或子系统之间交互方式频繁变化,外观模式可能会导致外观类变得庞大臃肿

实例

  • 现有三个子系统
  • 不使用外观模式
  • 使用外观模式

【结构型】组合模式

概念

  • 组合模式(Composite Pattern):一种结构型设计模式,它允许将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。
  • 设计意图:
    • 客户端可以一致地处理单个对象和组合对象。
    • 通过递归组合的方式来构建复杂的对象结构。
  • 组合模式适用于以下场景:
    • 需要表示对象的“部分-整体”层次结构时,例如文件系统、组织结构、UI组件树等。
    • 希望客户端可以忽略组合对象与单个对象的差异,统一地使用组合结构中的所有对象时。
  • 组合模式主要包含以下角色:
    • Component(组件):定义组合对象和叶子对象的接口。
    • Leaf(叶子):表示组合中的叶子对象,没有子对象。
    • Composite(组合):表示有子对象的组合对象,定义子对象的管理方法。
notion image
  • 优点:
    • 简化客户端代码,使得客户端可以一致地处理组合对象和单个对象。
    • 更容易添加新的类型的组件。
  • 缺点:
    • 使得设计变得更加复杂,特别是在需要管理大量对象时。
    • 可能会导致系统中的对象数量增加。

实例

  • 抽象类:Component
  • 叶子类:Leaf
  • 组合类:Composite
  • 实例:
  • 打印结果
notion image

【结构型】代理模式

概念

  • 代理模式(Proxy Pattern)是一种结构型设计模式,它通过代理对象控制对原对象的访问。代理模式可以为对象的访问提供额外的功能,例如控制访问权限、延迟加载、日志记录等。
  • 设计意图:代理模式的设计意图是为对象提供一个代理,以便在不改变对象接口的情况下,控制对对象的访问。代理模式可以用于以下几种情况:
    • 远程代理:为一个对象在不同地址空间提供局部代表。
    • 虚拟代理:根据需要创建开销很大的对象。
    • 保护代理:控制对原始对象的访问。
    • 智能引用代理:在访问对象时执行一些附加操作。
  • 代理模式主要由以下几个部分构成:
    • 接口(Subject):定义了代理类和真实类的公共接口。
    • 真实类(RealSubject):实现了接口的类,是真正需要被代理的对象。
    • 代理类(Proxy):实现了接口,并持有真实类的引用,控制对真实类的访问。
  • 优点
    • 控制访问:可以控制对真实对象的访问,增加安全性。
    • 延迟加载:可以延迟加载开销大的对象,提升性能。
    • 附加功能:可以在访问对象时添加额外的功能,如日志记录、性能监控等。
  • 缺点
    • 增加复杂性:引入代理对象会增加系统的复杂性。
    • 性能开销:代理模式会增加一些额外的性能开销,特别是在频繁访问的场景下。

实例

  • 定义银行账户接口,代理类和真实类的公共接口
  • 定义银行账户,真实类
  • 定义代理类
  • 使用
  • 打印结果

【结构型】适配器模式

概念

  • 适配器模式(Adapter Pattern):是一种结构型设计模式,它的主要目的是将一个类的接口转换成客户端希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以协同工作。适配器模式有两种实现方式:对象适配器和类适配器。
    • 对象适配器:通过继承的方式,将适配器类与被适配的对象关联起来。
    • notion image
    • 类适配器:通过组合的方式,将适配器类与被适配的类关联起来。
    • notion image
  • 构成
    • 目标接口(Target):定义客户端所需的接口。
    • 适配者(Adaptee):定义一个已经存在的接口,这个接口需要适配。
    • 适配器(Adapter):实现目标接口,并通过组合或继承的方式调用适配者的接口。
  • 优点
    • 可以让任何两个没有关联的类一起运行。
    • 提高了类的复用性。
    • 增加了类的透明性和灵活性。
  • 缺点
    • 过多地使用适配器会让系统变得复杂。
    • 由于引入了额外的适配器层,可能会影响性能。
  • 在游戏开发中的应用
    • 数据库访问:不同的数据库(如MySQL、MongoDB)有不同的访问接口。适配器模式可以将这些不同的接口统一成一个标准接口,简化数据库操作。
    • 第三方库集成:游戏开发中经常需要使用第三方库(如物理引擎、图形库)。适配器模式可以将这些库的接口转换为游戏引擎所需的接口,简化集成过程。
    • 旧代码复用:在游戏开发中,可能需要复用旧项目中的代码。适配器模式可以将旧代码的接口适配到新项目中使用,避免重写代码。

实例

  • 目标接口
  • 被适配者

对象适配器

  • 适配器
  • 客户端

类适配器

  • 适配器
  • 客户端

【结构型】桥接模式

定义

  • 桥接模式(Bridge Pattern)是一种结构型设计模式,旨在将抽象部分与其实现部分分离,使它们可以独立地变化;它通过组合而不是继承来实现这种分离。
  • 桥接模式的设计意图是:
    • 解耦抽象和实现:使得抽象和实现可以独立变化,不会相互影响。
    • 提高系统的扩展性:通过分离抽象和实现,可以更容易地扩展系统的功能。
  • 桥接模式适用于以下场景:
    • 当一个系统需要在多个维度上扩展时,例如形状和颜色的组合。
    • 当不希望在抽象类和实现类之间建立紧密耦合时。
    • 当系统希望避免由于增加实现类数量而导致的类的爆炸性增加时。
  • 桥接模式主要涉及以下几个组成部分:
    • 实现类接口(Implementor):定义实现类的接口,提供具体的实现。
    • 具体实现类(ConcreteImplementor):实现实现类接口,提供具体的实现方式。
    • 抽象类(Abstraction):定义了使用实现类接口的接口。
    • 扩展抽象类(RefinedAbstraction):实现抽象类所定义的接口,可能增加一些额外的方法。
  • 优点
    • 提高系统的扩展性:抽象和实现可以独立扩展。
    • 减少类的数量:通过组合而不是继承来减少类的数量。
  • 缺点:
    • 增加系统的复杂性:由于引入了额外的抽象层,系统的复杂性可能会增加。
notion image

实例

  • 实现类接口
  • 具体实现类
  • 抽象类
  • 扩展抽象类
  • 客户端代码

【结构型】享元模式

概念

  • 定义:享元模式是一种结构型设计模式,主要用于减少创建对象的数量,以减少内存占用和提高性能。它通过共享多个对象的部分状态来实现。
  • 享元模式适用于以下场景:
    • 系统中有大量相似对象,这些对象会占用大量内存。
    • 对象的大部分状态可以被外部化或共享。
    • 需要通过共享来降低内存占用,如数据库连接池、字符串缓存池等。
  • 享元模式主要由以下角色组成:
    • 抽象享元角色(Flyweight):通常是一个接口或抽象类,声明了具体享元类公共的方法。
    • 享元工厂角色(Flyweight Factory):负责创建和管理享元对象。
    • 具体享元角色(Concrete Flyweight):实现了抽象享元类,在该类中为内部状态提供了存储空间。
    • 非共享享元角色(Unsharable Flyweight):不能被共享的子类。
  • 优点:
    • 减少内存消耗:通过共享对象,降低了系统中对象的数量,从而减少内存占用。
    • 使用了相对独立的外部状态:不会影响内部状态,能使得享元对象在不同环境中被共享。
  • 缺点:
    • 享元模式需要区分外部状态和内部状态,使得应用程序某种程度上复杂化了。
    • 为了使对象可以共享,需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
暂时无法在飞书文档外展示此内容

实例

  • 抽象享元接口:
  • 具体享元类(可共享):
  • 具体享元类(非共享):
  • 享元工厂类:
  • 客户端代码
  • 打印结果

【结构型】装饰模式

概念

  • 装饰模式(Decorator Pattern)是一种结构型设计模式,可以动态地给对象添加新的行为,无需修改其代码。
  • 实现:装饰模式通过创建一个装饰类来包装原始类,从而在不改变原始类的情况下扩展其功能。装饰类和原始类具有相同的接口,这样客户端就可以透明地使用装饰类。
  • 装饰模式的设计意图:
    • 动态地给对象添加职责。
    • 通过使用多个不同的装饰类,可以在运行时组合出各种不同的行为。
  • 装饰模式由以下几个部分构成:
    • 组件接口(Component):定义对象的接口,可以是抽象类或接口。
    • 具体组件(ConcreteComponent):实现组件接口的类,表示被装饰的原始对象。
    • 装饰器(Decorator):实现组件接口的抽象类,包含一个指向组件对象的引用。
    • 具体装饰器(ConcreteDecorator):继承装饰器类,向组件添加新的行为。
  • 装饰模式适用于以下场景:
    • 需要在不修改原始类代码的情况下扩展类的功能。
    • 需要动态地添加或撤销对象的职责。
    • 需要通过组合不同的装饰类来实现复杂的功能。
  • 优点
    • 灵活性高:可以动态地添加或撤销对象的职责。
    • 遵循开闭原则:可以在不修改原始类的情况下扩展其功能。
    • 组合性强:可以通过组合多个装饰类来实现复杂的功能。
  • 缺点
    • 增加复杂性:由于使用了多个小对象,系统可能会变得复杂。
    • 调试困难:由于装饰器的嵌套,调试时可能难以追踪对象的行为。
notion image

实例

  • 组件接口
  • 具体组件
  • 装饰器抽象类,继承组件接口并持有组件成员变量
  • 具体装饰器
  • 客户端代码
  • 打印结果

【行为型】中介者模式

概念

  • 定义:中介者模式是一种行为型设计模式,主要用于降低多个对象和类之间的通信复杂性;中介者模式定义了一个中介对象来封装一系列对象之间的交互;使各对象之间不需要显式地相互引用,从而使其耦合松散,且可以独立地改变它们之间的交互
  • 作用:解决对象间复杂的一对多关联问题,避免对象之间的高度耦合,简化系统结构
  • 实现方式:
    • 定义中介者接口:规定中介者必须实现的接口
    • 创建具体中介者:实现中介者接口,包含协调各同事对象交互的逻辑
    • 定义同事类:各个对象不需要显式地相互引用,而是通过中介者来进行交互
  • 优点:
    • 降低复杂度:将多个对象间的一对多关系转换为一对一关系
    • 解耦:对象之间不再直接引用,通过中介者进行交互
    • 符合迪米特原则:对象只需知道中介者,不需要知道其他对象
  • 缺点:
    • 中介者复杂性:中介者可能会变得庞大和复杂,难以维护

实例

中介者模式包含以下几个主要角色:
  • 中介者(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(上下文):维护一个状态实例,这个实例定义了当前的状态。
notion image
  • 优点
    • 简化复杂状态转换逻辑:状态模式将与状态相关的行为分散到独立的状态类中,避免了在上下文类中使用大量的条件语句,从而简化了代码结构。
    • 提高可维护性和可扩展性:新的状态和状态转换可以通过添加新的状态类来实现,而不需要修改现有的代码,符合开闭原则。
    • 状态切换更清晰:状态模式使得状态切换更加明确和直观,每个状态类只负责处理其特定的行为和状态转换。
    • 封装状态:状态模式将状态和行为封装在独立的类中,使得状态的变化对其他类透明,减少了耦合。
  • 缺点
    • 类的数量增加:状态模式需要为每个具体状态创建一个类,可能会导致类的数量增加,增加系统的复杂性。
    • 状态之间的依赖:如果状态之间存在复杂的依赖关系,可能会导致状态类之间的耦合增加。
    • 状态切换的开销:状态切换可能会引入额外的开销,特别是在状态切换频繁的情况下。

实例

  • 状态接口
  • 具体状态:继承状态接口并实现其中处理状态的方法
  • 上下文类
  • 应用

【行为型】命令模式

概念

  • 命令模式(Command Pattern)是一种行为设计模式,它将请求封装成对象,从而使用户可以用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
  • 应用场景:
    • 需要参数化对象的操作:例如,菜单项的点击操作。
    • 需要将操作放入队列中执行:例如,任务调度系统。
    • 需要支持撤销操作:例如,文本编辑器中的撤销和重做功能。
  • 构成:
    • 命令接口(Command):声明执行操作的接口。
    • 接收者(Receiver):执行命令相关的操作。
    • 具体命令类(ConcreteCommand):持有接收者,实现命令接口,定义具体的操作。
    • 调用者(Invoker):持有命令对象,并在某个时间点调用命令对象的执行方法。
notion image

实例

  • 命令接口(Command)
  • 接收者(Receiver)
  • 具体命令类(ConcreteCommand)
  • 调用者(Invoker)
  • 客户端

【行为型】访问者模式

概念

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

实例

  • 访问者接口,使用函数重载实现访问不同的元素
  • 具体访问者,实现接口方法
  • 元素接口
  • 具体元素
  • 对象结构
  • 客户端代码
  • 打印结果

【行为型】策略模式

概念

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

实例

  • 策略接口
  • 具体策略:加法和减法
  • 上下文类
  • 客户端

【行为型】解释器模式

概念

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

实例

  • 抽象表达类
  • 终结符表达式
  • 非终结符表达式
  • 客户端

【行为型】模板方法模式

概念

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

实例

  • 抽象类
  • 具体类
  • 客户端
  • 打印结果
学习笔记:.NET网络通信模块与Unity网络开发学习笔记:计算机网络(自顶向下方法)课程笔记
Loading...
Latest posts
游戏算法-Floyd搜索算法知识梳理和通用框架
2025-4-2
游戏算法-A*搜索算法知识梳理和通用框架
2025-4-2
游戏AI行为决策-目标导向行为规划(GOAP)通用框架
2025-3-23
自制Python任务调度模块-MySchedule
2025-3-20
学习笔记:23种设计模式
2025-3-19
学习笔记:计算机网络(自顶向下方法)课程笔记
2025-3-15