状態モード
名前が示すように、状態モードは、状態マシンを実装するときに使用されるモードです。
組み込みソフトウェア開発では、さまざまな状態機械に遭遇することがよくあります。最も単純な例を見てみましょう。次の図に示すように、デバイスには2つの状態があります。
通常、ステートマシンを実装する疑似コードは次のとおりです。
enum StateEnum {
OpenState;
CloseState;
};
enum OperatinEnum {
LongPressButton;
ShortPressButton;
}
int StateProcess(int currentState, int operation)
{
if (operation == LongPressButton) {
if (currentState == OpenState) {
// ...
return CloseState;
}
} else if (operation == ShortPressButton)
if (currentState == CloseState) {
// ...
return OpenState;
}
}
// 状态切换失败,保持当前状态
return currentState;
}
以下に示すように、スリープ状態を増やしたい場合:
次に、コードを次のように変更する必要があります( "// – add"を含む行は、今回変更したコードです)。
enum StateEnum {
OpenState;
CloseState;
SleepState; //--add
};
enum OperatinEnum {
LongPressButton;
ShortPressButton;
FreeOver5Mins; //--add
}
int StateProcess(int currentState, int operation)
{
if (operation == LongPressButton) {
if (currentState == OpenState) {
// ...
return CloseState;
}
} else if (operation == ShortPressButton)
if (currentState == CloseState) {
// ...
return OpenState;
} else if (currentState == SleepState) { //--add
// ... //--add
return OpenState; //--add
}
} else if (operation == FreeOver5Mins) { //--add
if (currentState == OpenState) { //--add
// ... //--add
return SleepState; //--add
}
}
// 状态切换失败,保持当前状态
return currentState;
}
これは非常に単純な状態機械です。しかし、正直なところ、このレベルでは、コードが正しく実装されているかどうかを確認することが困難です。したがって、この実装の欠点は明らかです。1)if-elseが多すぎて複雑すぎ、比較的単純な状態機械でさえ一目で理解するのが難しい、2)開閉の原理に明らかに違反している。
それでは、GOF状態モデルによると、どのようにそれを達成する必要がありますか?上記のコードを「状態」で分割し、各状態を個別のクラスとして扱う必要があります。睡眠状態が増加すると、睡眠状態クラスが増加します。擬似コードは次のとおりです。
enum StateEnum {
OpenState;
CloseState;
SleepState; //--add
};
enum OperatinEnum {
LongPressButton;
ShortPressButton;
FreeOver5Mins; //--add
}
// 定义State基类
struct State {
struct State* (*LongPressButtonOperation)(); // LongPressButton的操作,返回next state
struct State* (*ShortPressButtonOperation)();
struct State* (*FreeOver5MinsOperation)(); //--add
}
// 定义OpenState类,继承State基类
struct OpenState {
... 根据本状态迁移的实际情况,重写基类中的方法
}
// 定义CloseState类,继承State基类
struct CloseState {
... 根据本状态迁移的实际情况,重写基类中的方法
}
// 定义SleepState类,继承State基类 //--add
struct SleepState { //--add
... 根据本状态迁移的实际情况,重写基类中的方法 //--add
}
// 定义StateProcessor(),驱动状态迁移
StateProcessor() {
...
}
ここでは、詳細に拡張するのではなく、状態モードの疑似コードを書いただけです。主な理由は、この実装方法は以前の方法より明らかに優れていると個人的に感じているからです。しかし、私はまだこのような状態機械を実装することはあまり良くないと感じています。この方法は主に状態の増加の問題を解決しますが、操作の増加の問題は解決しないため、実際には、状態マシンが変更されると、ほとんどのシナリオで状態と操作が変更されます。前の例と同様に、スリープ状態を増やすとFreeOver5Mins操作も増え、オープン状態を増やすとFreeOver5Mins操作も増えます。
とにかく、ステートマシンが状態が増加したときに操作を増加させない方法を見たことはありません。したがって、私は通常、状態マシンを別の方法で実装し、現在の各state-operation-next状態をクラスとして扱い、StateProcessorを使用して状態遷移を駆動します。
enum StateEnum {
OpenState;
CloseState;
SleepState; //--add
};
enum OperatinEnum {
LongPressButton;
ShortPressButton;
FreeOver5Mins; //--add
}
// 定义State--Operation基类
struct State {
int currentState;
int operation;
int (*Operation)();
int nextState;
}
struct State g_fsm[] = {
{ OpenState,
LongPressButton,
xxxOperation(), // 根据本状态迁移的实际情况,重写基类中的方法
CloseState
},
{ CloseState,
ShortPressButton,
xxxOperation(), // 根据本状态迁移的实际情况,重写基类中的方法
OpenState,
},
{ OpenState, //--add
FreeOver5Mins, //--add
xxxOperation(), //--add
SleepState, //--add
},
{ SleepState, //--add
ShortPressButton, //--add
xxxOperation(), //--add
OpenState, //--add
},
};
// 定义StateProcessor(),驱动状态迁移
int StateProcessor(int currentState, int operation) {
for (i = 0; i < g_fsm[]的成员数; i++) {
if (currentState == g_fsm[i].currentState) && (operation == g_fsm[i].operation) {
g_fsm[i].xxxOperation();
return g_fsm[i].nextState;
}
}
// 状态切换失败,保持当前状态
return currentState;
}
この方法はGOFの状態モードとは違うと思いますが、個人的にはこの方法の方が完璧だと思います。