C++设计模式之状态模式

【声明】本题目来源于卡码网(卡码网KamaCoder
【提示:如果不想看文字介绍,可以直接跳转到C++编码部分


设计模式大纲】

【简介】

--什么是状态模式(第20种设计模式)

状态模式 (State Pattern)是⼀种行为型设计模式 ,它适⽤于⼀个对象在不同的状态下有不同的行为时,⽐如说电灯的开、关、闪烁是不停的状态,状态不同时,对应的行为也不同,在没有状态模式的情况下,为了添加新的状态或修改现有的状态,往往需要修改已有的代码,这违背了开闭原则 ,而且如果对象的状态切换逻辑和各个状态的行为都在同⼀个类中实现,就可能导致该类的职责过重不符合单⼀职责原则

而状态模式将每个状态的行为封装在⼀个具体状态类中,使得每个状态类相对独⽴,并将对象在不同状态下的行为进⾏委托,从而使得对象的状态可以在运行时动态改变,每个状态的实现也不会影响其他状态。


【基本结构】

状态模式包括以下⼏个重要角色:

  • State (状态): 定义⼀个接口,⽤于封装与Context的⼀个特定状态相关的⾏为。
  • ConcreteState (具体状态): 负责处理Context在状态改变时的⾏为, 每⼀个具体状态⼦类实现⼀个与Context 的⼀个状态相关的⾏为。
  • Context (上下⽂): 维护⼀个具体状态⼦类的实例,这个实例定义当前的状态。

【基本实现】

1. 定义状态接口:

创建⼀个状态接⼝,该接⼝声明了对象可能的各种状态对应的⽅法。

java 复制代码
// 状态接⼝
public interface State {
    void handle();
}

2. 实现具体状态类:

为对象可能的每种状态创建具体的状态类,实现状态接⼝中定义的⽅法。

java 复制代码
// 具体状态类1
public class ConcreteState1 implements State {
    @Override
    public void handle() {
        // 执⾏在状态1下的操作
    }
}
// 具体状态类2
public class ConcreteState2 implements State {
    @Override
    public void handle() {
        // 执⾏在状态2下的操作
    }
}

3. 创建上下文类:

该类包含对状态的引用,并在需要时调⽤当前状态的⽅法。

java 复制代码
// 上下⽂类
public class Context {
    private State currentState;

    public void setState(State state) {
        this.currentState = state;
    }

    public void request() {
        currentState.handle();
    }
}

4. 客户端使用:

创建具体的状态对象和上下文对象,并通过上下文对象调用相应的⽅法。通过改变状态,可以改变上下⽂对象的行为

java 复制代码
public class Client {
    public static void main(String[] args) {
        Context context = new Context();

        State state1 = new ConcreteState1();
        State state2 = new ConcreteState2();

        context.setState(state1);
        context.request(); // 执⾏在状态1下的操作

        context.setState(state2);
        context.request(); // 执⾏在状态2下的操作
    }
}

【使用场景】

状态模式将每个状态的实现都封装在⼀个类中 ,每个状态类的实现相对独⽴ ,使得添加新状态或修改现有状态变得更加容易,避免了使⽤⼤量的条件语句来控制对象的行为。但是如果状态过多,会导致类的数量增加,可能会使得代码结构复杂。

总的来说,状态模式适用于有限状态机的场景,其中对象的⾏为在运⾏时可以根据内部状态的改变⽽改变,在游戏开发中,Unity3D 的 Animator 控制器就是⼀个状态机。它允许开发⼈员定义不同的状态(动画状态),并通过状态转换来实现角色的动画控制和⾏为切换。


【C++编码部分】

1. 题目描述

小明家有一个灯泡,刚开始为关闭状态(OffState)。台灯可以接收一系列的指令,包括打开("ON")、关闭("OFF")和闪烁("BLINK")。每次接收到一个指令后,台灯会执行相应的操作,并输出当前灯泡的状态。请设计一个程序模拟这个灯泡系统。

2. 输入描述

第一行是一个整数 n(1 <= n <= 1000),表示接收的命令数量。 接下来的 n 行,每行包含一个字符串 s,表示一个命令("ON"、"OFF"或"BLINK")。

3. 输出描述

对于每个命令,输出一行,表示执行该命令后灯泡的状态。

4. C++编程实例

cpp 复制代码
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file StateMode.hpp
* @brief 状态模式
* @autor 写代码的小恐龙er
* @date 2024/01/24
*/

#include <iostream>
#include <string>

using namespace std;

// 前置声明

//  状态接口 类
class State;

// 具体状态1 -- 打开
class StateOn;
// 具体状态2 -- 关闭
class StateOff;
// 具体状态3 -- 闪烁
class StateBlink;

// 上下文类 -- 关注的对象类 灯
class Light;

//  状态接口 类
class State{
// 成员接口函数
public:
    virtual string Handle() = 0;
};

// 具体状态1 -- 打开
class StateOn : public State
{
// 重载接口函数
public:
    string Handle() override{
        return "Light is ON";
    }
};

// 具体状态2 -- 关闭
class StateOff : public State
{
// 重载接口函数
public:
    string Handle() override{
        return "Light is OFF";
    }
};

// 具体状态3 -- 闪烁
class StateBlink : public State
{
// 重载接口函数
public:
    string Handle() override{
        return "Light is Blinking";
    }
};

// 上下文类 -- 关注的对象类 灯
class Light{
// 成员数据
private:
    // 灯的状态
    State *_state = nullptr;
// 成员函数 
public:
    // 构造函数
    Light(){
        this->_state = new StateOff();
    }
    
    // 设置状态
    void SetState(State *state){
        this->_state = state;
    }
    
    // 执行操作
    string HandleState(){
        return _state->Handle();
    }
};

int main()
{
    // 命令数量
    int orderNum = 0;
    std::cin >> orderNum;
    // 创建 上下文类 -- 灯泡
    Light *light = new Light();
    // 创建 状态基类
    State *state = nullptr;
    // 遍历输入
    for(int i = 0; i < orderNum; i++){
        // 指令类型
        string orderType = "";
        std::cin >> orderType;
        
        // 判断
        if(orderType == "ON"){
            state = new StateOn();
        }
        else if(orderType == "OFF"){
            state = new StateOff();
        }
        else if(orderType == "BLINK"){
            state = new StateBlink();
        }
        
        // 给灯设置状态
        light->SetState(state);
        // 打印信息
        string printInfo = light->HandleState();
        std::cout << printInfo << endl;
    }
    
    // 析构!
    delete light;
    light = nullptr;
    
    if(state != nullptr){
        delete state;
        state = nullptr;
    }

    return 0;
}


......

To be continued.

相关推荐
禁默37 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
yuyanjingtao40 分钟前
CCF-GESP 等级考试 2023年9月认证C++四级真题解析
c++·青少年编程·gesp·csp-j/s·编程等级考试
Cachel wood44 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Code哈哈笑1 小时前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
gb42152871 小时前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
程序猿进阶1 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
闻缺陷则喜何志丹1 小时前
【C++动态规划 图论】3243. 新增道路查询后的最短距离 I|1567
c++·算法·动态规划·力扣·图论·最短路·路径
zfoo-framework1 小时前
【jenkins插件】
java
风_流沙1 小时前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch