C++ 中策略模式与状态模式的区别

2025年03月22日 | 阅读 10 分钟

C++ 具有两种行为设计模式:状态模式策略模式。然而,它们的功能是不同的。由于策略模式,对象可以在运行时从多种算法中选择以更改其行为。忽略对象的内部状态,其主要目标是封装可互换的算法。另一方面,状态模式封装了特定于状态的行为,允许对象随着其内部状态的变化而改变其行为。策略模式将算法与客户端分离,而状态模式控制对象状态的变化。策略和状态处理由状态驱动的行为。然而,两者都提供了灵活性。在本文中,我们将讨论策略模式与状态模式之间的区别。在讨论它们的区别之前,我们必须了解策略模式和状态模式及其特性。

什么是策略模式?

策略模式是一种行为设计模式,它允许在运行时选择算法。它包含其定义家族中的所有算法,并使它们可互换。因此,算法可以在不影响使用它的客户端的情况下进行更改。这使其非常适合需要根据情况使用不同方法或策略,而又不影响对象主要功能的情况。

每个算法都包含在策略模式定义的类中。它允许客户端在不更改对象的基本逻辑的情况下动态地切换策略。无论选择哪种算法或“策略”,客户端都可以始终以相同的方式与它们进行交互,因为它们都符合相同的接口。

策略模式的关键组成部分

策略模式的几个关键组成部分如下:

  1. Context (上下文):提及该方法的类。它与称为 Strategy 的对象交互,该对象指定应用程序算法。
  2. Strategy (策略):这是一个描述算法接口的抽象基类。各种策略使用相同的方法,并从此基类派生。
  3. Concrete Strategies (具体策略):这些类实现了 Strategy 接口中指定的算法的不同变体。

C++ 中策略模式的特点

C++ 中策略模式的几个关键特点如下:

  1. 接口隔离:每种策略都有一个由模式定义的抽象类或通用接口。除了保持接口整洁之外,它还可以确保每个具体策略类仅实现对该特定算法至关重要的方法。
  2. 运行时行为更改:通过更改策略对象,可以在运行时修改类的行为。这使得创建更动态和灵活的系统成为可能,这些系统可以适应不断变化的需求。
  3. 遵循开闭原则:开闭原则允许在不修改现有代码的情况下添加新策略。这使得在需求变化时更容易扩展系统以包含新算法。
  4. 上下文与策略解耦:策略模式分离了上下文(应用策略的类)和策略本身。它允许在不影响上下文类的情况下更改策略。
  5. 组合优于继承:策略模式鼓励使用组合而不是继承来更改行为。通过根据需要合并不同的策略来动态创建行为,可以实现更灵活的设计。

策略模式的优点

C++ 中策略模式的几个优点如下:

  1. 算法封装:通过允许将相关算法封装在不同的类中,策略模式有助于组织和简化代码。每种策略都有独立的更改能力,而不会影响其他策略。
  2. 算法选择灵活性:无需更改客户端代码,我们就可以通过在运行时选择多种策略来修改对象的行为。因此,系统变得更具适应性和可扩展性。
  3. 开闭原则:此设计遵循开闭原则,因为它允许在不修改现有代码的情况下添加新策略。可以在不影响策略接口或上下文的情况下添加其他算法。

策略模式的缺点

C++ 中策略模式的几个缺点如下:

  1. 类数量增加:由于每种策略都需要自己的类,这可能会导致类过多并增加系统的整体复杂性。
  2. 特定于上下文的策略逻辑:策略有时可能包含特定于其情况的逻辑,这可能违反单一职责原则。这意味着设计可能会变得不那么清晰,因为它依赖于客户端的特定细节。
  3. 开销:如果策略非常小,开发多个类和接口的成本可能不值得。此外,在运行时更改策略可能会带来性能开销。
  4. 设置复杂性:在处理需要协调多个策略的项时,策略的设置可能需要额外的复杂性。与更简单的替代方案相比,这增加了设计的复杂性。

示例

让我们举一个例子来说明 C++ 中的策略模式

输出

 
Executing the strategy A
Executing the strategy B   

说明

这个 C++ 程序展示了策略模式,该模式允许在运行时动态选择算法。Strategy 类是一个抽象基类,它定义了所有策略必须实现的 execute() 函数。两个具体策略,ConcreteStrategyAConcreteStrategyB,提供了它们对 execute() 函数的实现,该函数将不同的消息打印到控制台。Context 类维护一个指向 Strategy 对象的指针,该对象最初通过其构造函数设置。setStrategy() 方法允许在不同策略之间进行运行时切换,而 executeStrategy() 方法调用当前选定策略的 execute() 函数。Context 在 main() 函数中以 ConcreteStrategyA 开始,然后切换到 ConcreteStrategyB 并执行两种策略。这种模式通过将算法与使用它的上下文分离开来,促进了灵活性。

什么是状态模式?

状态模式是一种行为设计模式,它允许对象根据其内部状态的变化来调整其行为。与其使用许多条件语句,不如使用它来表达对象的各种状态以及它们之间的转换。此模式在 C++ 中对于描述行为因状态而异且可能处于多种可能状态之一的对象很有用。

此模式通过让状态对象本身处理状态转换,从而减少了对管理状态更改的大型条件语句(如 if-else 或 switch 语句)的需求,从而提高了灵活性。更模块化、可读且可维护的代码得以实现。

对于 C++ 中的每种状态,状态模式都指定一个不同的类,这些类实现了与该状态相关的操作。由于对象(上下文)将行为委托给当前状态对象,因此它允许在运行时进行动态修改。由于它们具有通用接口,因此上下文可以轻松地在状态类之间切换。

状态模式的关键组成部分

状态模式的几个关键组成部分如下:

  1. State Interface (状态接口) (State):这是定义所有具体状态类的通用接口的抽象类。
  2. Concrete State Classes (具体状态类) (ConcreteStateA, ConcreteStateB):状态接口的实现,它们指定了特定的行为。
  3. Context Class (上下文类) (Context):此类通过在具体状态之间切换来操作行为,同时存储状态对象的实例。

状态模式的特点

状态模式的几个特点如下:

  1. 状态封装:每个状态都由实现共享接口的独立类表示。这种封装允许基于对象的状态控制其行为,而无需复杂的条件。
  2. 可重用性:通过使用此方法,可以在不修改当前代码的情况下添加新状态。通过创建实现相同接口的新状态类,可以鼓励开闭原则和代码重用。
  3. 状态转换管理:上下文类能够切换状态并跟踪当前状态。这种管理使得状态转换更容易,而无需更改上下文的实现方式,从而获得更清晰、更易于维护的代码。
  4. 清晰的结构:该模式将特定于状态的行为划分为独立的类,从而提供了一个结构化和有组织的结构。由于每个类都有明确定义的职责,因此它有助于理解和扩展系统。

状态模式的优点

状态模式的几个优点如下:

  1. 状态封装:各种状态和转换包含在模式内,并与主要逻辑分开维护。
  2. 开闭原则:通过在不修改现有代码的情况下轻松添加新状态,满足了开闭原则。
  3. 更清晰的转换逻辑:该模式通过消除用于管理多种状态的复杂 if-else 或 switch 语句来提高可维护性。

状态模式的缺点

状态模式的几个优点如下:

  1. 多个类的开销:此模式可能会增加更多类,这可能会使其更复杂。在这方面,它与策略模式相似。
  2. 内存使用:使用多个状态对象,尤其是在状态很多的情况下,可能会导致内存使用量增加。

用例

状态模式的几个用例如下:

  1. 用户界面应用程序:不同的状态,包括加载、错误和空闲状态,其中行为因情况而异。
  2. 游戏开发:管理游戏角色或对象的状态(例如,行走、跳跃或攻击)。
  3. 协议实现:在网络协议中模拟不同的状态,例如打开、关闭或等待确认。

示例

让我们举一个例子来说明 C++ 中的状态模式

输出

 
Handling the state A behavior
Handling the state B behavior   

说明

此 C++ 应用程序演示了状态模式,该模式允许 对象 根据其内部状态的变化而改变行为。为了使每个状态能够 工作,程序首先定义一个具有纯虚函数 handle() 的 State 接口。此方法用于在两种具体状态 ConcreteStateA 和 ConcreteStateB 中提供特定于状态的行为。Context 类调用当前状态的 handle() 方法,并维护一个指向当前状态的智能指针。在 main 函数中设置初始状态(ConcreteStateA)后,request() 方法会调用当前状态的行为。然后上下文切换到新状态(ConcreteStateB),展示行为如何根据状态变化动态调整。此实现使用智能指针 (unique_ptr) 来有效管理状态内存,确保在状态更改时自动释放资源。

C++ 中策略模式和状态模式之间的主要区别

Difference between Strategy and State Patterns in C++

策略模式和状态模式之间存在几个主要区别。一些主要区别如下:

方面策略模式状态模式
目的它允许在运行时选择算法。它允许对象根据其状态更改其行为。
背景上下文持有对策略接口的引用。上下文维护对当前状态的引用。
行为它通过实现不同的策略来更改对象的行为。它基于内部状态转换,这会修改行为。
封装每个策略代表一个特定的算法。每个状态都封装了特定于状态的活动。
状态表示策略不依赖于上下文的状态。状态取决于当前状态下上下文的状态。
灵活性无需更改上下文即可添加新策略。添加新状态的代码无需更改上下文。
使用示例选择排序方法(快速排序、合并排序等)。一个在播放、暂停和停止之间切换的媒体播放器。
决策逻辑通常,该方法基于外部因素或条件语句。上下文中的条件语句已最小化,因为转换由状态对象处理。
实现开销对于不同的算法,这可能会导致大量策略类。对于不同类型的行为,这可能会导致许多状态类。

结论

总之,策略模式侧重于封装算法,以便客户端可以在运行时选择和切换它们。

另一方面,状态模式侧重于控制与状态相关的行为,允许对象响应其内部状态的变化而修改其行为。尽管它们用于不同的场景和不同的目的,但这两种模式都提高了应用程序的灵活性和可维护性。


下一个主题C++ 编译器