zoukankan      html  css  js  c++  java
  • 21 行为型模式-----状态模式

    模式动机(State Pattern)软件系统中,每一个模块在不同的环境下可能发挥着不同的作用,表现为同一对象可能有多种不同的状态,而每种状态下可能有不同的行为。在UML图中,可以用状态图来表示。在程序设计中,我们引入一个抽象状态接口,其中封装了与当前环境状态相关的行为,然后定义具体的状态实现类,根据状态的不同实现不同的行为,并且负责状态之间的切换操作。

     

    参与者:

    TCPConnection:(当前工作环境 Context):维护一个状态接口的实例,这个实例表示当前环境所处的状态。

    TCPState:(抽象状态接口 State):定义一个接口,封装与Context的状态相关的一系列行为。

    TCPState/TCPListen/TCPClosed定义具体状态的行为实现,并且负责在不同状态之间的切换工作。

     

    Context实际上就是拥有不同状态的对象,Context将与当前状态相关的行为实现委托给具体的状态类处理。客户用具体状态配置Context,配置完毕后,不需要再与具体状态之间交互了,之后完全可以通过Context类进行操作。

    之所以设计状态类,是因为Context有多种状态,如果在Context类中通过分支语句实现不同状态的逻辑判断,代码显得非常庞大,而且也不利于修改和维护。因此,将不同的状态及其对应的行为封装到不同的类中,有利于理解整体的软件设计结构。

     

    状态模式将所有与某个特定的状态相关的行为都放入一个对象中,只需实现抽象状态接口即可增加新的状态。但是新增状态必须修改状态转换代码,否则无法切换到新的状态。一般而言,系统当前只能有一份某个具体状态的实例,因此可以将其引用设为static类型。同时如果不同的状态对象只是以类型来区分,而不涉及只与自身相关的内部状态,那么该对象就可以设计为享元对象,以节约系统空间。

     

    模式结构图:

     

     

    模式代码:

    bt_状态模式.h:

     1 #ifndef SP_H
     2 #define SP_H
     3 #include <iostream>
     4 #include <string>
     5 using namespace std;
     6 
     7 /*
     8     TCP连接
     9 */
    10 class TCPState;
    11 class TCPClosed;
    12 class TCPConnection
    13 {
    14 public:
    15     TCPConnection();
    16     void ActiveOpen();
    17     void PassiveOpen();
    18     void Close();
    19     void Send();
    20 
    21 private:
    22     friend class TCPState;
    23     void ChangeState(TCPState* s);
    24 
    25 private:
    26     TCPState* state;
    27 };
    28 
    29 /*
    30     TCP状态接口
    31 */
    32 class TCPState
    33 {
    34 public:
    35     virtual ~TCPState();
    36     virtual void ActiveOpen(TCPConnection* conn);
    37     virtual void PassiveOpen(TCPConnection* conn);
    38     virtual void Close(TCPConnection* conn);
    39     virtual void Send(TCPConnection* conn);
    40 
    41 protected:
    42     virtual void ChangeState(TCPConnection* conn, TCPState* s);
    43 };
    44 
    45 /*
    46     TCP建立状态
    47 */
    48 class TCPEstablished : public TCPState
    49 {
    50 public:
    51     static TCPState* Instance();
    52     virtual void Close(TCPConnection* conn);
    53     // ...
    54 };
    55 
    56 /*
    57     TCP监听状态
    58 */
    59 class TCPListen : public TCPState
    60 {
    61 public:
    62     static TCPState* Instance();
    63     virtual void Send(TCPConnection* conn);
    64     // ...
    65 };
    66 
    67 /*
    68     TCP关闭状态
    69 */
    70 class TCPClosed : public TCPState
    71 {
    72 public:
    73     static TCPState* Instance();
    74     virtual void ActiveOpen(TCPConnection* conn);
    75     virtual void PassiveOpen(TCPConnection* conn);
    76     // ...
    77 };
    78 
    79 #endif // SP_H

    bt_状态模式.cpp:

     1 #include "bt_状态模式.h"
     2 
     3 /* TCP连接 */
     4 TCPConnection::TCPConnection()
     5 {
     6     cout << "Default TCPConnection State (Closed)" << endl;
     7     state = TCPClosed::Instance();
     8 }
     9 void TCPConnection::ActiveOpen(){ state->ActiveOpen(this); }
    10 void TCPConnection::PassiveOpen(){ state->PassiveOpen(this); }
    11 void TCPConnection::Close(){ state->Close(this); }
    12 void TCPConnection::Send(){ state->Send(this); }
    13 
    14 void TCPConnection::ChangeState(TCPState* s){ state = s; }
    15 
    16 /* TCP状态接口 */
    17 TCPState::~TCPState(){  }
    18 void TCPState::ActiveOpen(TCPConnection* conn){  }
    19 void TCPState::PassiveOpen(TCPConnection* conn){  }
    20 void TCPState::Close(TCPConnection* conn){  }
    21 void TCPState::Send(TCPConnection* conn){  }
    22 
    23 void TCPState::ChangeState(TCPConnection* conn, TCPState* s){ conn->ChangeState(s); }
    24 
    25 /* TCP建立状态 */
    26 TCPState* TCPEstablished::Instance(){ return new TCPEstablished; }
    27 void TCPEstablished::Close(TCPConnection* conn)
    28 {
    29     cout << "TCPEstablished::Close (Established ---> Closed)" << endl;
    30     ChangeState(conn, TCPClosed::Instance());
    31 }
    32 
    33 /* TCP监听状态 */
    34 TCPState* TCPListen::Instance(){ return new TCPListen; }
    35 void TCPListen::Send(TCPConnection* conn)
    36 {
    37     cout << "TCPListen::Send (Listen ---> Established)" << endl;
    38     ChangeState(conn, TCPEstablished::Instance());
    39 }
    40 
    41 /* TCP关闭状态 */
    42 TCPState* TCPClosed::Instance(){ return new TCPClosed; }
    43 void TCPClosed::ActiveOpen(TCPConnection* conn)
    44 {
    45     cout << "TCPClosed::ActiveOpen (Closed ---> Established)" << endl;
    46     ChangeState(conn, TCPEstablished::Instance());
    47 }
    48 void TCPClosed::PassiveOpen(TCPConnection* conn)
    49 {
    50     cout << "TCPClosed::PassiveOpen (Closed ---> Listen)" << endl;
    51     ChangeState(conn, TCPListen::Instance());
    52 }

    测试用例.cpp:

     1 #include "bt_状态模式.h"
     2 
     3 int main()
     4 {
     5     cout << "***** 状态模式测试 *****" << endl;
     6     TCPConnection* conn = new TCPConnection;    // 默认状态下为Closed状态
     7     conn->PassiveOpen();                        // 被动打开转为Listen状态
     8     conn->Send();                               // 发送信息需要转为Established状态
     9     conn->Close();                              // 转为Closed状态
    10 
    11     delete conn;
    12 
    13     return 0;
    14 }
    
    

    模式总结:

    :: 状态模式的设计主要是为了简化多重分支语句,增加代码简洁性,易于维护。

    :: 状态模式不强制指定哪一个参与者定义状态转换规则。如果状态转换规则可以确定保持不变,那么由Context类实现也完全可以;然而令具体状态类指定转换规则会更加灵活,这也是我们经常用到的状态模式实现方式。

    :: 状态模式并不能很好地支持“开闭原则”,新增状态时必须修改状态转换代码,否则无法切换到新的状态。

    :: 与用查找表定义的转换映射相比,状态模式侧重于与特定状态相关的行为实现;而表模式侧重于定义状态转换规则,其难以加入伴随状态发生的一系列动作。

     

     

  • 相关阅读:
    在Ubuntu中通过update-alternatives切换软件版本
    SCons: 替代 make 和 makefile 及 javac 的极好用的c、c++、java 构建工具
    mongodb 的使用
    利用grub从ubuntu找回windows启动项
    How to Repair GRUB2 When Ubuntu Won’t Boot
    Redis vs Mongo vs mysql
    java script 的工具
    python 的弹框
    how to use greendao in android studio
    python yield的终极解释
  • 原文地址:https://www.cnblogs.com/benxintuzi/p/4577183.html
Copyright © 2011-2022 走看看