状态模式(状态机)
以前写状态机,比较常用的方式是用 if-else 或 switch-case,高级的一点是函数指针列表。最近,看了一文章《c语言设计模式–状态模式(状态机)》(来源:embed linux share,作者:亚索老哥)),原来状态机还可以这么简单地玩~~
亚索老哥提出的状态机六步法
(1)、定义状态接口
(2)、定义系统当前状态指针
(3)、定义具体状态,根据状态迁移图来实现具体功能和状态切换
(4)、定义主程序上下文操作接口
(6)、主程序通过上下文操作接口来控制系统当前状态的变化
亚索老哥的状态机例程
场景:
- 设计一个简单的MP3播放器,要求两个按键(播放/暂停、停止)分别控制MP3的播放/停止功能
按键功能:
- [play/pause] 播放/暂停
- [stop] 停止
状态迁移图:
#include <stdio.h>
/*********************************************** 1、定义状态接口,以MP3的状态接口为例,每种状态下都可能发生 两种按键动作。 ************************************************/
typedef struct State{
void (* stop)();
void (* palyOrPause)();
}State;
/*********************************************** 2、定义系统当前状态指针,保存系统的当前状态 ************************************************/
State * pCurrentState;
/*********************************************** 3、定义具体状态,根据状态迁移图来实现具体功能和状态切换。 ************************************************/
void ignore();
void startPlay();
void stopPlay();
void pausePlay();
void resumePlay();
//空闲状态时,stop键操作无效,play/pause会开始播放音乐
State IDLE = {
ignore,
startPlay
};
//播放状态时,stop键会停止播放音乐,play/pause会暂停播放音乐
State PLAY = {
stopPlay,
pausePlay
};
//暂停状态时,stop键会停止播放音乐,play/pause会恢复播放音乐
State PAUSE = {
stopPlay,
resumePlay
};
void ignore()
{
//空函数,不进行操作
}
void startPlay()
{
//实现具体功能
printf("开始播放音乐\n");
//进入播放状态
pCurrentState = &PLAY;
}
void stopPlay()
{
//实现具体功能
printf("停止播放音乐\n");
//进入空闲状态
pCurrentState = &IDLE;
}
void pausePlay()
{
//实现具体功能
printf("暂停播放音乐\n");
//进入暂停状态
pCurrentState = &PAUSE;
}
void resumePlay()
{
//实现具体功能
printf("恢复播放音乐\n");
//进入播放状态
pCurrentState = &PLAY;
}
/*********************************************** 4、定义主程序上下文操作接口,主程序只关心当前状态,不关心状态之间 是怎么变化的。 ************************************************/
void onStop();
void onPlayOrPause();
State context = {
onStop,
onPlayOrPause
};
void onStop(State *pThis)
{
pCurrentState->stop(pThis);
}
void onPlayOrPause(State *pThis)
{
pCurrentState->palyOrPause(pThis);
}
/*********************************************** 5、初始化系统当前状态指针,其实就是指定系统的起始状态 ************************************************/
void init()
{
pCurrentState = &IDLE;
}
/*********************************************** 6、主程序通过上下文操作接口来控制系统当前状态的变化 ************************************************/
void main()
{
init();
context.palyOrPause();//播放
context.palyOrPause();//暂停
context.palyOrPause();//播放
context.stop();//停止
}
模拟一个状态机
TODO
小结
亚索老哥的状态机六步法,有许多优点,还是借用原话:
- 代码结构要更加清晰,避免了过多的switch…case或者if…else语句 的使用。
- 很好地体现了开闭原则和单一职责原则,每个状态都是一个子结构体,你要增加状态就要增加子结构体,你要修改状态,你只修改一个子结构体就可以了。
- 封装性非常好,状态变换放置到子结构体的内部来实现,外部的调用不用知道子结构体的内部如何实现状态和行为的变换。
还没有评论,来说两句吧...