我正在编写一个有限状态机(FSM)类,它应该从各种其他派生类继承(作为Arduino项目的一部分)。 派生类需要将布尔方法传递给基本FSM类触发状态更改。方法保存在地图中。在主循环中调用它们时,它们将通过映射中的方法来查看状态更改是否适用。
由于FSM类需要调用派生类的方法,因此我根据派生类的类将FSM类编写为模板类。在(T& obj)上应用该方法的对象被传递给构造函数:
template <class T> class FiniteStateMachine {
public:
FiniteStateMachine(int numberOfStates, int initialState, T& obj);
typedef bool (T::*TransitionCondFunction)(void);
void addTransition(int fromState, int toState, TransitionCondFunction transitionFunction);
void loop();
private:
int _numStates;
int _state;
T& _obj; // the object to apply the functions on
map<int,map<int,TransitionCondFunction>> _transitionMap;
}
template<class T>
FiniteStateMachine<T>::FiniteStateMachine(int numberOfStates, int initialState, T& obj) :
_numStates(numberOfStates), _state(initialState), _obj(obj), _transitionMap() {}
template<class T>
void FiniteStateMachine<T>::addTransition(int fromState, int toState, TransitionCondFunction transitionFunction){
_transitionMap[fromState][toState] = transitionFunction;
}
template<class T>
void FiniteStateMachine<T>::loop(){
auto it = _transitionMap.find(_state);
if (it != _transitionMap.end()){
map<int,TransitionCondFunction> innerTransMap = it->second;
for(typename map<int,TransitionCondFunction>::iterator iter = innerTransMap.begin(); iter != innerTransMap.end(); ++iter) {
bool (T::*tf)(void) = iter->second;
// is condition for transition fullfilled?
if ((_obj.*tf)()) {
int toState = iter->first;
// ok, transit to next state
_state = toState;
break;
}
}
}
else {
printf("Cannot find transition condition function for state %d\n", _state);
}
}
具体派生类需要这样:
enum MyState {STATE0, STATE1, STATE2, NUM_STATES};
class MyTransitionClass : public FiniteStateMachine<MyTransitionClass>{
public:
MyTransitionClass(int numberOfStates, int initialState) :
FiniteStateMachine(numberOfStates, initialState, *this){
addTransition(STATE0, STATE1, t1);
}
bool t1(){return _x>0;}
private:
int _x = 99;
};
使用(在单元测试中)将是这样的:
TEST(FiniteStates_test, testWithInheritedClass){
MyTransitionClass mc = MyTransitionClass(2,STATE0);
EXPECT_EQ(STATE0, mc.getState());
mc.loop();
EXPECT_EQ(STATE1, mc.getState());
}
这有效,但我想知道是否还有其他选择。使用派生类作为模板类型来实例化模板类并不“感觉”最佳。
有什么建议吗?