最近认真学习了一下设计模式中的一个比较简单的:状态模式,并用它设计了一个极其简单的“登录过程”的代码。
状态模式的优势:
- 当系统中存在的状态很多(一般>=4),但状态的相互跳转并不复杂,即每个状态的出度较少(一般为1~3),这种情况下适合用状态模式;
- 状态模式下,状态之间的跳转由状态对象自己负责,每个状态自己知道且只知道自己的跳转方法,这样设计起来简单,系统不需要同样管理状态之间的跳转。
- 状态模式的优点在于能方便的进行状态之间的跳转,修改状态调整规则,以及扩展新的状态;
收获如下:
- 要使用设计模式来设计系统的话,需要先画出UML图来,或者是类似的图,比如使用状态模式,就应该先画出类图(静态图)和状态图来;
- 状态模式要先弄清楚有哪些状态,有哪些能产生状态转换的函数;
- 极为简单的情况,可以用switch|if-else实现,但是复杂的情况,就应该使用状态模式,而且状态模式更加规范,易于维护和扩展;
- 状态模式有多种实现方法,下面的这种方法是其中比较好的方法。
类图和状态图:
代码:
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