C++状态机

803 项目里面的subproc用到了状态机。上报平台时终端会切换不同的报文,这里就用上了状态机,很妙!这个插件的整体流程我写在《苏标上报协议流程》里面,这篇文章仔细地写下状态机。

整体流程如下:

整体流程

为什么用状态机

优雅!其实这个插件的功能用switch也可以,但是这样略显臃肿。状态机用到了C++的继承、虚函数,初次看到有些惊艳,原来代码还能这么写!(原谅我很无知)

状态机是什么

状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。

状态机有四个概念:

  1. State ,状态。一个状态机至少要包含两个状态。
  2. Event ,事件。事件就是执行某个操作的触发条件或者口令。这个插件里面执行完一个状态的事件后切换到下一个状态。
  3. Action ,动作。事件发生以后要执行动作。
  4. Transition ,变换。也就是从一个状态变化为另一个状态。

状态机如何使用

现在已经离职,我靠印象写个简易版本的吧。

state_machine.hpp

#include <iostream>
#include <unistd.h>

using namespace std;

/**
 * 状态处理返回结果类
*/
class TAccyResult
{
public:
    enum TAccyResultTypeTag
    {
        kTypeStateNone = 0,     ///< 无状态
        kTypeStateSuccess,      ///< 该状态处理请求结果成功
        kTypeStateFail,         ///< 该状态处理请求结果失败
        kTypeStateWait,         ///< 该状态正在处理请求
        kTypeStateNext,         ///< 进行下一个状态
    };
    typedef enum TAccyResultTypeTag TAccyResultType;

public:
    TAccyResult()
    {
        result_ = kTypeStateNone;
    }
    ~TAccyResult()
    {

    }

public:
    void setResult(TAccyResultType result) {result_ = result;}
    TAccyResultType &GetResult() {return result_;}

private:
    TAccyResultType result_;
};

/**
 * 上报请求类
 * 没有具体的业务, 就随便写写
*/
class TAccyRequest
{
public:
    int id;
};

class TStateBase;
class TStateA;
class TStateB;
class TStateC;
class TStateFail;
class TStateSuccess;

/**
 * 状态机类
 * 维护当前状态的对象, 设置下一状态
*/
class TContext{
public:
    TContext();
    ~TContext() {}

public:
    /**
     * 状态机处理请求
     * @param : request 当前请求
     * @note : 传入请求, 调用当前状态对象的handle进行处理
    */
    TAccyResult HandleRequest(TAccyRequest *request);

    /**
     * 修改状态机的当前状态
     * @param : next_state 下一状态
    */
    void ChangeState(TStateBase *next_stase) {next_stase_ = next_stase;}

private:
    TStateBase *cur_state_;  ///<  当前状态
    TStateBase *next_stase_; ///< 下一状态临时指针
};

/*
抽象状态类
具体状态继承此类, 重写对应Handle
*/
class TStateBase
{
public:
    virtual ~TStateBase() {}
    /**
     * 状态处理接口
     * @param : request 请求指针
     * @param : context 状态机指针
     * @note : 处理传入的请求,调用状态机的ChangeState更改当前状态
     * @return : 返回对应TResult
    */
    virtual TAccyResult Handle(TAccyRequest *request, TContext *context) = 0;

protected:
    TStateBase() {}
};

/**
 * A状态具体状态类
 * @note : 睡眠一秒后进入B状态
*/
class TStateA : public TStateBase
{
public:
    TStateA() { cout << "TSAtateA" << endl; }
    ~TStateA() override {}

public:
    TAccyResult Handle (TAccyRequest *request, TContext *context) override;
};

/**
 * B状态具体状态类
 * @note : 睡眠一秒后进入C状态
*/
class TStateB : public TStateBase
{
public:
    TStateB() { cout << "TSAtateB" << endl; }
    ~TStateB() override {}

public:
    TAccyResult Handle (TAccyRequest *request, TContext *context) override;
};

/**
 * C状态具体状态类
 * @note : 睡眠一秒后状态机运行成功
*/
class TStateC : public TStateBase
{
public:
    TStateC() { cout << "TSAtateC" << endl; }
    ~TStateC() override {}

public:
    TAccyResult Handle (TAccyRequest *request, TContext *context) override;
};

/**
 * 失败具体状态类
 * @note : 断开连接、清理文件...
*/
class TStateFail : public TStateBase
{
public:
    TStateFail() { cout << "TStateFail" << endl; }
    ~TStateFail() override {}

public:
    TAccyResult Handle (TAccyRequest *request, TContext *context) override;
};

/**
 * 成功具体状态类
 * @note : 断开连接
*/
class TStateSuccess : public TStateBase
{
public:
    TStateSuccess() { cout << "TStateSuccess" << endl; }
    ~TStateSuccess() override {}

public:
    TAccyResult Handle (TAccyRequest *request, TContext *context) override;
};

/*-------------------------------*/

/**
 * 状态机处理请求
 * @param : request 当前请求
 * @note : 传入请求, 调用当前状态对象的handle进行处理
*/
TAccyResult TContext::HandleRequest(TAccyRequest *request)
{
    TAccyResult result;

    if (cur_state_ != NULL)
    {
        result = cur_state_->Handle(request, this);
        /// 运行到下一状态
        if (result.GetResult() == TAccyResult::kTypeStateNext)
        {
            /// 进行下一状态, 释放当前的状态内存, 把下一状态对象赋值给当前状态
            free(cur_state_);
            cur_state_ = next_stase_;
            next_stase_ = nullptr;
        }
        /// 状态运行结束
        else if (result.GetResult() == TAccyResult::kTypeStateSuccess || result.GetResult() == TAccyResult::kTypeStateFail)
        {
            free(cur_state_);
        }
    }
    else
    {
        result.setResult(TAccyResult::kTypeStateFail);
    }
    return result;
}

state_machine.cpp

#include "state_machine.hpp"

TContext::TContext() { cur_state_ = new TStateA(); }

TAccyResult TStateA::Handle(TAccyRequest *request, TContext *context)
{
    TAccyResult result;
    sleep(1);
    cout << "TStateA Handle" << endl;
    context->ChangeState(new TStateB());
    result.setResult(TAccyResult::kTypeStateNext);
    return result;  
}

TAccyResult TStateB::Handle (TAccyRequest *request, TContext *context) 
{
    TAccyResult result;
    sleep(1);
    cout << "TStateB Handle" << endl;
    context->ChangeState(new TStateC());
    result.setResult(TAccyResult::kTypeStateNext);
    return result;
}

TAccyResult TStateC::Handle (TAccyRequest *request, TContext *context) 
{
    TAccyResult result;
    sleep(1);
    cout << "TStateC Handle" << endl;
    context->ChangeState(new TStateSuccess());
    result.setResult(TAccyResult::kTypeStateNext);
    return result;
}

TAccyResult TStateFail::Handle (TAccyRequest *request, TContext *context) 
{
    TAccyResult result;
    sleep(1);
    cout << "TStateFail Handle" << endl;
    result.setResult(TAccyResult::kTypeStateFail);
    return result;
}

TAccyResult TStateSuccess::Handle (TAccyRequest *request, TContext *context) 
{
    TAccyResult result;
    sleep(1);
    cout << "TStateSuccess Handle" << endl;
    result.setResult(TAccyResult::kTypeStateSuccess);
    return result;
}

int main()
{
    bool processing = true;
    TContext *context = new TContext();

    while (1)
    {
        if (processing)
        {
            if (context == nullptr)
            {
                context = new TContext();
            }
            else
            {
                TAccyResult result = context->HandleRequest(nullptr);
                if (result.GetResult() == TAccyResult::kTypeStateSuccess)
                {
                    free(context);
                    processing = false;
                }
                else if (result.GetResult() == TAccyResult::kTypeStateFail)
                {
                    free(context);
                    processing = false;
                }
            }
        }
        else break;
    }

    return 0;
}

这样是不行的,使用了未定义类型“B”

class B;
class A {
public:
    A() {
        B* p = new B();
    }
};

class B {
public:
    B() {}
};

所以使用的时候要在hpp里面声明,cpp里面实现。

运行结果如下,某一状态执行结束后切换到下一状态

file

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇