【设计模式之状态模式 -- C++】

状态模式 -- 状态切换,行为变化

状态模式(State Pattern)允许一个对象在其内部状态改变时改变它的行为。这种模式下,对象看起来似乎修改了它的类。状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。将状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。

组成
  1. 定义状态接口(State):这个接口将封装与上下文的一个特定状态相关的行为。

  2. 创建具体状态类(Concrete States):这些类实现了状态接口,每个类对应一种状态,并实现在该状态下应有的行为。

  3. 定义上下文(Context):这个类包含一个指向状态对象的引用,这个引用可以用来改变其行为。

实现伪代码:

cpp 复制代码
// State 接口声明了特定状态下的行为
interface State {
    method1();
    method2();
}

// ConcreteStateA 和 ConcreteStateB 实现了 State 接口
class ConcreteStateA : State {
    method1() { // 实现细节 }
    method2() { // 实现细节 }
}

class ConcreteStateB : State {
    method1() { // 实现细节 }
    method2() { // 实现细节 }
}

// Context 类包含一个 State 类型的对象,并允许设置当前状态
class Context {
    private State state;

    setState(State state) {
        this.state = state;
    }

    method1() {
        state.method1();
    }

    method2() {
        state.method2();
    }
}
优点
  1. 封装性:状态模式通过将每个状态封装到一个类中,将与状态相关的行为局部化,并且将不同状态的行为分割开来,增强了系统的封装性。
  2. 去除庞大的条件分支语句:状态模式避免了在操作中使用大量的条件分支语句,使得状态的转换更加明确,且易于管理和维护。
  3. 扩展性:由于状态是由类表示的,所以可以很容易地添加新的状态,符合开闭原则。
  4. 职责清晰:每个状态类只关注于一种状态的行为实现,使得职责分配明确。
使用场景
  1. 对象的行为依赖于其状态:当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变其行为时,可以使用状态模式。
  2. 复杂的条件分支需要简化:当一个操作中包含庞大的多分支结构,并且这些分支依赖于对象的状态时,状态模式可以将每一分支转换为一个状态类的一个实现。
  3. 跨类的状态转换:当状态的转换逻辑分散在多个类中时,使用状态模式可以将这些逻辑集中管理,使得状态转换更加清晰和集中。
  4. 状态模式也常用于实现有限状态机:在需要通过一系列输入导致不同状态之间转换和操作的场景中,状态模式提供了一种清晰的方式来实现这种机制。

总的来说,状态模式适用于对象状态多变且相互依赖,需要在运行时根据状态改变对象行为的场景。通过使用状态模式,可以使得状态转换逻辑更加清晰,易于扩展和维护。

实现
  1. state接口
cpp 复制代码
class State {
public:
    virtual void handleRequest() = 0;
    virtual ~State() = default;
};
  1. 具体状态实现a,b
cpp 复制代码
class ConcreteStateA : public State {
public:
    void handleRequest() override {
        std::cout << "ConcreteStateA handles request." << std::endl;
    }
};
class ConcreteStateB : public State {
public:
    void handleRequest() override {
        std::cout << "ConcreteStateB handles request." << std::endl;
    }
};
  1. 上下文
cpp 复制代码
class Context {
private:
    std::unique_ptr<State> state;
public:
    Context(std::unique_ptr<State> state) : state(std::move(state)) {}
    void setState(std::unique_ptr<State> newState) {
        state = std::move(newState);
    }
    void request() {
        state->handleRequest();
    }
};
  1. 测试
cpp 复制代码
int main() {
    Context context(std::make_unique<ConcreteStateA>());
    context.request(); // 输出: ConcreteStateA handles request.

    context.setState(std::make_unique<ConcreteStateB>());
    context.request(); // 输出: ConcreteStateB handles request.

    return 0;
}
  1. 结果
shell 复制代码
ConcreteStateA handles request.
ConcreteStateB handles request.
相关推荐
ragnwang1 小时前
C++ Eigen常见的高级用法 [学习笔记]
c++·笔记·学习
lqqjuly4 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
冰红茶兑滴水5 小时前
云备份项目--工具类编写
linux·c++
刘好念5 小时前
[OpenGL]使用 Compute Shader 实现矩阵点乘
c++·计算机图形学·opengl·glsl
酒鬼猿6 小时前
C++进阶(二)--面向对象--继承
java·开发语言·c++
姚先生976 小时前
LeetCode 209. 长度最小的子数组 (C++实现)
c++·算法·leetcode
小王爱吃月亮糖7 小时前
QT开发【常用控件1】-Layouts & Spacers
开发语言·前端·c++·qt·visual studio
aworkholic7 小时前
opencv sdk for java中提示无stiching模块接口的问题
java·c++·opencv·jni·opencv4android·stiching
程序员老冯头7 小时前
第十六章 C++ 字符串
开发语言·c++
Xenia2237 小时前
复习篇~第二章程序设计基础
c++·算法