学习设计模式系列之二:状态模式

最近认真学习了一下设计模式中的一个比较简单的:状态模式,并用它设计了一个极其简单的“登录过程”的代码。

状态模式的优势:

  1. 当系统中存在的状态很多(一般>=4),但状态的相互跳转并不复杂,即每个状态的出度较少(一般为1~3),这种情况下适合用状态模式;
  2. 状态模式下,状态之间的跳转由状态对象自己负责,每个状态自己知道且只知道自己的跳转方法,这样设计起来简单,系统不需要同样管理状态之间的跳转。
  3. 状态模式的优点在于能方便的进行状态之间的跳转,修改状态调整规则,以及扩展新的状态;

收获如下:

  1. 要使用设计模式来设计系统的话,需要先画出UML图来,或者是类似的图,比如使用状态模式,就应该先画出类图(静态图)和状态图来;
  2. 状态模式要先弄清楚有哪些状态,有哪些能产生状态转换的函数;
  3. 极为简单的情况,可以用switch|if-else实现,但是复杂的情况,就应该使用状态模式,而且状态模式更加规范,易于维护和扩展;
  4. 状态模式有多种实现方法,下面的这种方法是其中比较好的方法。

类图和状态图:

代码:

  1 #include <stdlib.h>
  2 
  3 inline void P(const char* str)
  4 {
  5     printf("%s
", str);
  6 }
  7 
  8 // 用状态模式设计客户端登录过程
  9 class Dialog;
 10 class State
 11 {
 12 protected:
 13     Dialog* dlg;
 14 public:
 15     State(Dialog* d): dlg(d){}
 16 
 17     // 定义能产生状态转换的方法
 18     virtual void click()=0;
 19     virtual void success()=0;
 20     virtual void close()=0;
 21 };
 22 
 23 class Start: public State
 24 {
 25 public:
 26     // 调用父类的构造函数
 27     Start(Dialog* d): State(d){}
 28     void click();
 29     void success(){};
 30     void close();
 31 };
 32 class Loading: public State
 33 {
 34 public:
 35     // 调用父类的构造函数
 36     Loading(Dialog* d): State(d){}
 37     void click();
 38     void success();
 39     void close();
 40 };
 41 class Main: public State
 42 {
 43 public:
 44     // 调用父类的构造函数
 45     Main(Dialog* d): State(d){}
 46     void click(){};
 47     void success(){};
 48     void close();
 49 };
 50 class Closed: public State
 51 {
 52 public:
 53     // 调用父类的构造函数
 54     Closed(Dialog* d): State(d){}
 55     void click(){};
 56     void success(){};
 57     void close(){};
 58 };
 59 
 60 
 61 class Dialog
 62 {
 63 private:
 64     State *state, *start, *loading, *main, *closed;
 65     bool is_active;
 66 public:
 67     Dialog(): is_active(true)
 68     {
 69         start = new Start(this);
 70         loading = new Loading(this);
 71         main = new Main(this);
 72         closed = new Closed(this);
 73         state = start;
 74     }
 75     // 状态的set接口
 76     void setStart(){state = start;}
 77     void setLoading(){state = loading;}
 78     void setMain(){state = main;}
 79     void setClosed(){state = closed;}
 80 
 81     // 
 82 
 83     // 产生状态转换的函数
 84     void click(){state->click();}
 85     void success(){state->success();}
 86     void close(){state->close();}
 87     void print()
 88     {
 89         if(state == start)
 90             P("START");
 91         else if(state == loading)
 92             P("LOADING");
 93         else if(state == main)
 94             P("MAIN");
 95         else if(state == closed)
 96             P("CLOSED");
 97     }
 98 };
 99 
100 // 实现函数接口
101 void Start::click()
102 {
103     dlg->setLoading();
104 }
105 void Loading::click()
106 {
107     dlg->setStart();
108 }
109 void Loading::success()
110 {
111     dlg->setMain();
112 }
113 void Start::close()
114 {
115     dlg->setClosed();
116 }
117 void Loading::close()
118 {
119     dlg->setClosed();
120 }
121 void Main::close()
122 {
123     dlg->setClosed();
124 }
125 
126 int _tmain(int argc, _TCHAR* argv[])
127 {
128     Dialog dlg;
129     char ch;
130     while(true)    // 消息循环
131     {
132         ch = getchar();
133         switch(ch)
134         {
135         case 'c':    // 执行click函数
136             dlg.click();
137             dlg.print();
138             break;
139         case 'q':    // 执行close函数
140             dlg.close();
141             dlg.print();
142             break;
143         case 's':    // 执行success函数
144             dlg.success();
145             dlg.print();
146             break;
147         default:
148             break;
149         }
150     }
151     system("pause");
152     return 0;
153 }

输出:

c
LOADING
c
START
c
LOADING
s
MAIN
q
CLOSED
原文地址:https://www.cnblogs.com/zanzan101/p/3396424.html