803 项目里面的subproc用到了状态机。上报平台时终端会切换不同的报文,这里就用上了状态机,很妙!这个插件的整体流程我写在《苏标上报协议流程》里面,这篇文章仔细地写下状态机。
整体流程如下:
为什么用状态机
优雅!其实这个插件的功能用switch也可以,但是这样略显臃肿。状态机用到了C++的继承、虚函数,初次看到有些惊艳,原来代码还能这么写!(原谅我很无知)
状态机是什么
状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。
状态机有四个概念:
- State ,状态。一个状态机至少要包含两个状态。
- Event ,事件。事件就是执行某个操作的触发条件或者口令。这个插件里面执行完一个状态的事件后切换到下一个状态。
- Action ,动作。事件发生以后要执行动作。
- 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里面实现。
运行结果如下,某一状态执行结束后切换到下一状态