• 程序设计模式 —— State 状态模式


    我应该如何阅读?


     

    本文将使用优雅的文字风格来告诉你什么是状态模式。

    注意:

      1.在阅读本文之前请保证你已经掌控了 面对对象的思想与 多态的基本概念,否则将难以理解。

      2.本文实现将用C++实现,你不一定必须学会C++,这些代码都有非常丰富的注释和简单的语法。

      3.请不要跳着看,除非你已经学会。

    那么现在开始吧


    或许你会以为是类的各种状态,其实差不多。但是还有各种行为

    允许一个对象在其内部状态改变时改变它的行为。实例化的对象看起来似乎修改了它的类

    首先,状态,顾名思义你应该就差不多明白。它可以表示一个类中的状态,但是不仅仅只是状态。

    它也包括了 行为,有点儿类似于策略模式,但是又不是策略模式。

      我一直坚信。这个设计模式,只需要仅仅一张图片即可完成说明:这张三个片段代表飞机的三个不同状态

    你懂了吗?根据日常生活的常识,你应该明白飞机这几种状态,但是我相信你应该还不太明白如何实现具体代码。

      你也应该明白 “没有动力” 的时候是不能飞行的。

      你也应该明白 “正在飞行” 的时候是不能再飞行的。

    正是因为如此,我们就可以直接在不同的状态子类,实现不同的方法,比如 “没有动力” 的时候,如果使用 “起飞” 成员函数,将会提示没有动力,起飞失败。

    而 “没有飞行” 的时候却是可以 使用 “起飞” 成员函数。

    那么我应该具体怎么做?


    实现的代码很简单。并且有丰富的注释,希望你能理解。

    大致框架图:

    飞机类是可以使用 任何一个 状态类,表示不同的状态。

    注意:如果你不会 C++,也没有关系,”Virtual” 关键字你可以无视,至于成员函数后面有一个 "=0",你可以理解为抽象方法,子类必须实现它,用Java的思想去看待代码

    状态类的基类

    下面我们来具体实现:基类永远都是这么简单,对吧?

     1 /* 状态类的基类 抽象类*/
     2 class State
     3 {
     4 public:
     5     State()
     6     {
     7 
     8     };
     9     virtual ~State()
    10     {
    11 
    12     };
    13     virtual void fly()=0;    //起飞   =0是纯虚函数,可以理解为子类必须实现的 抽象方法
    14     virtual void stopfly()=0;    //停止飞行,降落
    15     virtual void up()=0;        //拉升飞行高度
    16     virtual void down()=0;        //拉低飞行高度
    17 
    18 };

    实现状态类的各个子类

    然后我们应该来实现 各种状态了

    代码有点多,但是都是很容易的。而且有丰富的注释。。

      1 //状态类: 正在飞行 状态类
      2 class StateFlying : public State
      3 {
      4 public:
      5     StateFlying()
      6     {
      7         
      8     };
      9     virtual ~StateFlying()
     10     {
     11         
     12     };
     13     virtual void fly()
     14     {
     15         //因为飞机正在飞行,所以不能再度起飞
     16         cout << "ERROR: Can't do this!! You are not 'stopfly'! " <<endl;
     17     };    //起飞
     18     virtual void stopfly()    
     19     {
     20         //正在飞行的时候当然可以降落
     21         cout << "INFO: OK! stopfly" << endl;
     22     };    //停止飞行,降落
     23     virtual void up()    
     24     {
     25         //目前的状况当然可以这样做
     26         cout << "INFO: OK! up" << endl;
     27     };    //拉升飞行高度
     28     virtual void down()    
     29     {
     30         //目前的状况当然可以这样做
     31         cout << "INFO: OK! down" << endl;
     32     };    //拉低飞行高度
     33 };
     34 
     35 //状态类: 停机状态
     36 class StateNotFly : public State
     37 {
     38 public:
     39     StateNotFly()
     40     {
     41         
     42     };
     43     virtual ~StateNotFly()
     44     {
     45         
     46     };
     47     virtual void fly()
     48     {
     49         //因为是 停机状态,所以是可以起飞的
     50         cout << "INFO: OK! " << endl;
     51     };    //起飞
     52     virtual void stopfly()    
     53     {
     54         //你难道可以 停机之后 再停机么?
     55         cout << "ERROR: Can't do this!! You are not 'Flying'! " <<endl;
     56     };    //停止飞行,降落
     57     virtual void up()    
     58     {
     59         //停机的时候这些空中动作就算了吧
     60         cout << "ERROR: Can't do up!! You are not 'Flying'! " <<endl;
     61     };    //拉升飞行高度
     62     virtual void down()    
     63     {
     64         //停机的时候这些空中动作就算了吧
     65         cout << "ERROR: Can't do down!! You are not 'Flying'! " <<endl;
     66     };    //拉低飞行高度
     67 };
     68 
     69 //状态类: 没有动力状态
     70 class StateNotPower : public State
     71 {
     72 public:
     73     StateNotPower()
     74     {
     75 
     76     };
     77     virtual ~StateNotPower()
     78     {
     79 
     80     };
     81     virtual void fly()
     82     {
     83         //没有动力了,无法起飞!
     84         cout << "ERROR: Can't do fly!! You are not Power!  " <<endl;
     85     };    //起飞
     86     virtual void stopfly()    
     87     {
     88         //没有动力了,赶紧降落
     89         cout << "INFO: OK! stopfly" << endl;
     90     };    //停止飞行,降落
     91     virtual void up()    
     92     {
     93         //没有动力,你是没法爬升的,等死吧!
     94         cout << "ERROR: Can't do up!! You are not Power!  " <<endl;
     95     };    //拉升飞行高度
     96     virtual void down()    
     97     {
     98         //没有了动力了,但是可以 滑翔下降
     99         cout << "INFO: OK! down" << endl;
    100     };    //拉低飞行高度
    101 };
    102 
    103 /*
    104 如果你学过其他设计模式,或者了解代码复用,你可能会说上面的代码可以复用(我是指各个成员函数中的输出),完全不必要这样写。
    105 这里仅仅只是为了举例,尽量少的牵扯到其他。
    106  */

    这样,我们的三个状态就好了。从代码中你也可以看见一件事情,每个状态都有自己的各自的具体处理。

    但是你现在可能会问,为什么要浪费时间写这么多看起来都是差不多的功能呢?

    其实这样的话,你在飞机类里面就会出现一种现象,就是需要一个个判断当前的状态然后做相应的事情。类似于这样:

     1 //假设你要执行停飞,但是不使用状态模式,将会有这种代码的出现
     2 if(/*当前不是飞行ing*/)
     3 {
     4     //提示不能停飞
     5 }
     6 if(/*当前是飞行*/)
     7 {
     8     //执行停飞
     9 }
    10 if(/*当前没有动力*/)
    11 {
    12     //不能停飞
    13 }

    这种代码不但枯燥无趣,而且难以维护。如果哪天你加了一个“即将坠机”的状态,你需要修改每个类的每个方法。。。

    实现飞机类 AirPlane

    好了,回归正题,我们来实现飞机!看看飞机是如何不需要进行 状态 判断就可以直接用:

     1 /*这是 飞机类  这个类才是正在 在用上面的各种类*/
     2 class AirPlane
     3 {
     4 private:
     5     string name;
     6     State *state;    //状态
     7 
     8 public:
     9     AirPlane()
    10     {
    11         this->state = new StateNotPower();    //初始化状态为 “没有动力” 状态
    12     };
    13     ~AirPlane()
    14     {
    15         delete this->state;    //记得释放喔~
    16     };
    17     void setName(const char* name)
    18     {
    19         this->name = name;    //复制
    20     }
    21     void setState(State * state)
    22     {
    23         delete this->state;    //先释放原来的
    24         this->state = state;    //改成新的 状态
    25     };
    26     void fly()
    27     {
    28         cout << "[AirPlane][" << this->name << "] ";
    29         this->state->fly();
    30     };    //起飞
    31     void stopfly()    
    32     {
    33         cout << "[AirPlane][" << this->name << "] ";
    34         this->state->stopfly();
    35     };    //停止飞行,降落
    36     void up()    
    37     {
    38         cout << "[AirPlane][" << this->name << "] ";
    39         this->state->up();
    40     };        //拉升飞行高度
    41     void down()    
    42     {
    43         cout << "[AirPlane][" << this->name << "] ";
    44         this->state->down();
    45     };        //拉低飞行高度
    46     //你可以发现,我们将具体的实现全部交给了 子类去实现,我们完全不必管到底如何进行。
    47     //当然了,如果你会策略模式,或许你能更加灵活运用,策略模式与本模式很相似。
    48 };

    你可以看见,我们已经将方法全部委托给了 状态 类。对吧。这有什么问题?

    你根本无需在乎飞机到底是什么状态,完全就是直接用 状态类 的方法就好了。

    现在我们来战斗吧


     

    “作为 Pattern Art Online (AR)空战游戏的 元老玩家。你接到上级命令需要赶快去前线实行救援,你的队友几乎已经死绝了,你感到万分悲伤,你决定报仇”

    “但是 你本来就很少上前线,因为你已经普升到 军长了,但是你手上已经没有任何战斗飞行员了,你必须亲自上阵,因为如果一旦退缩的话,后面就是你的家乡”

     1 #include "State.h"
     2 
     3 using namespace std;
     4 
     5 int main(int argc, char const *argv[])
     6 {
     7     /*
     8         你实例化了一架 新的飞机,这个时候 作为 Pattern Art Online 游戏的 元老玩家。
     9         你需要赶过去支援你的 队友!
    10         前线目前已经非常紧张,导致你起飞的动作僵硬无比。
    11     */
    12     /*好的,我创建了一架飞机*/
    13     AirPlane *air = new AirPlane();
    14     /*随便取个名字,Alier Two 号*/
    15     air->setName("Alier Tow");
    16     /*起飞吧!我要赶快去 救我的队友*/
    17     air->fly();    /*输出: ERROR: Can't do fly!! You are not Power!*/
    18     /*该死,太紧张了,毕竟时间紧,你,就你,快加满油!*/
    19     air->setState(new StateNotFly());    //状态改成一切就绪,但没有正在飞行
    20     /*很好,油满了,给我拉升!*/
    21     air->up();    /*输出: ERROR: Can't do up!! You are not 'Flying'!*/
    22     /*可恶,忘记先发动 螺旋桨了。。。*/
    23     air->fly();    /*输出: INFO: OK!*/
    24     /*哈哈哈,飞起来了!*/
    25     air->setState(new StateFlying());    //状态改成 飞行ing
    26     /*给我飞高点*/
    27     air->up();    /*输出: INFO: OK! up*/
    28 
    29     /* ---五个小时的飞行后---*/
    30 
    31     /*咦?怎么回事,螺旋桨不转了?*/
    32     air->setState(new StateNotPower());
    33     /*卧槽,忘记带后备用油了,我可是要飞到 北美洲去啊!总部,总部!请求加油机支援!!!*/
    34     /*可恶。给我飞高点!!!*/
    35     /* ---距离地面还剩 800米--- */
    36     air->up();    /*输出: ERROR: Can't do up!! You are not Power!*/
    37     /*不...不要啊!不管什么,给我飞起来啊!!!*/
    38     air->fly();    /*救命啊: ERROR: Can't do fly!! You are not Power!*/
    39     /* ---即将坠机--- */
    40     /* ...砰... */
    41     /* --- You die--- */
    42 
    43     cin.get();
    44 
    45     delete air;        /*可怜的你,还没有飞到前线就坠机了,真是.....*/
    46     return 0;
    47 }

    输出:

    那么,你现在明白了?状态模式。你可以轻松的复用。甚至可以定义N个状态,定义个N不同的飞机,并且飞机与状态这之间却可以轻松的反复重用!

    因为状态都继承了 State 抽象类,而飞行则只管使用,定义状态,而不需要管理不同状态下的不同行为。

    就这样结束了?


     

    “你的队友对你十分失望,你的上司对你的飞行技术感到质疑,这是一个不好的现象,这意味着你很有可能要被逐出 【Fly!Fly!Fly!】战队。”

    “那么。你不准备做什么?”

    “听说 Pattern Art Online (VR)角色扮演类游戏开始了,你的队友貌似挺感兴趣,你决心要利用黑客技术来帮助自己取得队友的信任。

    故事后续情节请看:《程序设计模式——策略模式》

    最后


      但是要注意的一点,不是说有了这个模式,就必须要加进去使用,程序会更棒。

    设计模式要与你的程序相互和谐,不能写个 “HelloWorld” 程序都用到了设计模式。

    总的一句话,设计模式不是规则,而是你随时可以改变的模式。这也是很多设计模式书籍强调的一点。

    不论对你是否有帮助,还是谢谢您的耐心查看。如有错误之处,还望指教。

  • 相关阅读:
    export环境变量 & bash shell使用命令和环境变量
    crontab定时任务
    sh脚本
    Linux的用户及权限相关
    HTTP基础
    群晖Synology
    Cntlm
    oracle存储过程
    ORACLE 增加两列字段
    excel 公式 insert 语句
  • 原文地址:https://www.cnblogs.com/suwings/p/5925781.html
Copyright © 2020-2023  润新知