当前位置:   article > 正文

设计模式:状态机模式_状态机设计模式

状态机设计模式

首先状态机模式是处理一个类在内部状态改变的时候,其方法处理信息的模式也会改变;

这里说一个在RTS游戏里的应用:有限状态机。

我们要赋予每个战斗单位一个智能,比如一定范围内检测到地方单位,且自身处于游荡或者Patrol状态,那么就转换为攻击状态,再比如我们给这个单位一个通往目的地的路径,那么这个单位会自动前往目的地,如果到达目的地,那么就进入Idle状态。

这里我们可以写一个状态管理类:

  1. class StateSystem{
  2. void State state;
  3. public:
  4. void Run(){
  5. if(state==State::Idle){
  6. //...
  7. if(传递路径){
  8. LeaveState();
  9. state==State::Path;
  10. InitState();
  11. }
  12. }else if(state==State::Path){
  13. //...
  14. if(//到达终点){
  15. LeaveState();
  16. state=State::Idle;
  17. InitState();
  18. }
  19. }else if(state==State::Patrol){
  20. //...
  21. if(周边有敌人){
  22. LeaveState();
  23. state=State::Attack;
  24. InitState();
  25. }
  26. }else if(state==State::Attack){
  27. //...
  28. if(敌人被消灭){
  29. LeaveState();
  30. state=Satte::Idle;
  31. InitState();
  32. }
  33. }
  34. }
  35. void InitState(){
  36. if(state==State::Idle){
  37. //...
  38. }else if(state==State::Path){
  39. //...
  40. }else if(state==State::Patrol){
  41. //...
  42. }else if(state==State::Attack){
  43. //...
  44. }
  45. }
  46. void LeaveState(){
  47. if(state==State::Idle){
  48. //...
  49. }else if(state==State::Path){
  50. //...
  51. }else if(state==State::Patrol){
  52. //...
  53. }else if(state==State::Attack){
  54. //...
  55. }
  56. }
  57. }

可以看到,典型的bad smell,这里我们可以将每个状态抽象出来,设计好接口,然后用多态来替代if_else。

这个就是状态机模式的精髓,因为处理的问题就是一个类的方法处理信息的模式和类的状态有关,那么换句话说技术类中的每个状态都要处理相同的信息,那么我们为什么不把这种状态抽离出来呢,然后单独考虑呢?这样我们可以在原本的类中存储这些类的抽象接口,然后通过接口来调用这些状态。

看以下代码:

  1. #include<unordered_map>
  2. enum State {
  3. Idle,Patrol,Path,Attack,None
  4. };
  5. class State_Ifc {
  6. State state;
  7. public:
  8. virtual void Init() = 0;//初始化状态
  9. virtual void Leave() = 0;//卸载状态
  10. virtual void Run() = 0;//处理信息
  11. virtual State Reason() = 0;//转移到其他状态
  12. virtual State GetState() { return state; }
  13. };
  14. class IdleState :public State_Ifc {
  15. //....重写
  16. };
  17. class PatrolState :public State_Ifc {
  18. //....重写
  19. };
  20. class PathState :public State_Ifc {
  21. //....重写
  22. };
  23. class AttackState :public State_Ifc {
  24. //....重写
  25. };
  26. class StateSystem {
  27. State_Ifc* Current;//当前的状态
  28. std::unordered_map<State, State_Ifc*> map;
  29. //
  30. public:
  31. void UpData() {
  32. Current->Run();
  33. }
  34. void Trans() {
  35. State temp = Current->Reason();
  36. if (temp != State::None) {
  37. Current->Leave();
  38. Current = map[temp];
  39. Current->Init();
  40. }
  41. }
  42. };

这样子的话,State不依赖于具体的状态,而是依赖于抽象接口,这样子的话,就为拓展带来了可能。

但是,这个模式也有坏处,那就是没当添加新的状态,如果这个状态有和其他状态有转换,那么我们就不得不修改源代码,这里,本菜想,可以通过中介者模式来解决这个问题,具体方法是将
Reason方法从State子类中抽离出来,这样,我们修改转换时,只需要修改Mediator类即可:

具体如下:

  1. #include<unordered_map>
  2. #include<list>
  3. enum State {
  4. Idle,Patrol,Path,Attack,None
  5. };
  6. class Mediator_Ifc {
  7. public:
  8. virtual State Trans(State stateS, State stateE) = 0;
  9. };
  10. class State_Ifc {
  11. std::list<State> list;
  12. State state;
  13. Mediator_Ifc* Mediator;
  14. public:
  15. virtual void Init() = 0;//初始化状态
  16. virtual void Leave() = 0;//卸载状态
  17. virtual void Run() = 0;//处理信息
  18. virtual State Reason() {
  19. for (auto t : list) {
  20. State temp = Mediator->Trans(state, t);
  21. if (temp != State::None) {
  22. return temp;
  23. }
  24. }
  25. return State::None;
  26. }
  27. virtual State GetState() { return state; }
  28. };
  29. class IdleState :public State_Ifc {
  30. //....重写
  31. };
  32. class PatrolState :public State_Ifc {
  33. //....重写
  34. };
  35. class PathState :public State_Ifc {
  36. //....重写
  37. };
  38. class AttackState :public State_Ifc {
  39. //....重写
  40. };
  41. class MediatorCenter :public Mediator_Ifc {
  42. State Trans(State stateS, State stateE) {
  43. //...实现
  44. }
  45. };
  46. class StateSystem {
  47. Mediator_Ifc* Mediator;
  48. State_Ifc* Current;//当前的状态
  49. std::unordered_map<State, State_Ifc*> map;
  50. //
  51. public:
  52. void UpData() {
  53. Current->Run();
  54. }
  55. void Trans() {
  56. State temp = Current->Reason();
  57. if (temp != State::None) {
  58. Current->Leave();
  59. Current = map[temp];
  60. Current->Init();
  61. }
  62. }
  63. };

这样就可以了。

总之一句话:状态机模式是处理一个类在内部状态改变的时候,其方法处理信息的模式也会改变;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/385613
推荐阅读
相关标签
  

闽ICP备14008679号