zoukankan      html  css  js  c++  java
  • 学习设计模式系列之二:状态模式

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

    状态模式的优势:

    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
  • 相关阅读:
    使用C#开发ActiveX控件
    安装Python 3.6
    SDL 2.0 API by Category
    SDL的基础知识以及利用SDL播放视频
    区块链的java实现
    区块链工业架构设计
    微服务架构的优势与不足
    微服务架构设计
    FFmpeg常用基本命令
    FFmpeg进行屏幕录像和录音
  • 原文地址:https://www.cnblogs.com/zanzan101/p/3396424.html
Copyright © 2011-2022 走看看