• 设计模式 ——状态模式


    “状态变化”模式

    在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?“状态变化”模式应运而生。
    典型模式 :State、 Memento

    State 状态模式

    在实际开发中,经常会遇到,一个对象有多种状态,在每一个状态下,都有不同的行为。如下:

     1 typedef enum tagState
     2 {
     3      state0,
     4      state1,
     5      state2
     6 }State;
     7 
     8 //根据不同的state执行不同的DoSomrthing,就实际上相当于不同的Handle
     9 void Handle(State state)
    10 {
    11      if (state == state0){
    12           // DoSomethingA
    13      } else if (state == state1){
    14           // DoSomethingB
    15      } else if (state == state2){
    16           // DoSomethingC
    17      }else {
    18           // DoSomethingD
    19      }
    20 }
    21 
    22 //等效于根据不同的state调用不同的Handle
    23 void Handle(state0) { //Do somethingA }
    24 void Handle(state1) { //Do somethingB }
    25 void Handle(state2) { //Do somethingC }
    26 void Handle(other) {  //Do somethingD }

    每当新增状态时,就需要添加if-else分支,修改原来的代码,违反“开闭原则”,而且大量的分支结构,使得代码难以理解与维护。

    动机

    • 在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。
    • 如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转换之间引入紧耦合?

    定义

    允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。  ——《设计模式》GOF

    有了状态模式之后,可以解决随着状态增加而出现的多分支结构,将状态处理分散到各个状态子类中去,每个子类处理一种状态,因而使得状态的处理和转换变得清晰明确。

    结构

    Context:定义客户端感兴趣的接口,并且维护一个ConcreteState子类的实例,这个实例定义当前状态;
    State:定义一个接口以封装与Context的一个特定状态相关的行为;
    ConcreteState A/B:每一个子类实现一个与Context的一个状态相关的行为。

    它们之间的协作步骤:

    1. Context将与状态相关的请求委托给当前的ConcreteState对象处理;
    2. Context可以将自身作为一个参数传递给处理该请求的状态对象。这使得状态对象可以在必要时访问Context;
    3. Context是客户使用的主要接口。客户可用状态对象来配置一个Context,一旦一个Context配置完毕,它的客户不再需要直接与状态对象打交道。

    代码实现

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Context;
     5 
     6 //状态基类,为不同的状态规范统一的接口,当然可以有Handle1,Handle2...
     7 class State {
     8    public:
     9     virtual void Handle(Context* pContext) = 0;
    10 };
    11 
    12 //如最开始的实例代码,将if-else拆散为不同状态下的Handle处理函数
    13 class ConcreteStateA : public State {
    14    public:
    15     virtual void Handle(Context* pContext) { cout << "I am concreteStateA
    "; }
    16 };
    17 
    18 class ConcreteStateB : public State {
    19    public:
    20     virtual void Handle(Context* pContext) { cout << "I am concreteStateB
    "; }
    21 };
    22 
    23 //客户使用的主要接口。用状态对象来配置一个Context
    24 class Context {
    25    public:
    26     Context(State* pState) : m_pState(pState) {}
    27 
    28     //根据多态的特性会实际调用到指定状态的处理函数
    29     void Request() {
    30         if (m_pState) {
    31             m_pState->Handle(this);
    32         }
    33     }
    34 
    35     void ChangState(State* pState) { m_pState = pState; }
    36 
    37    private:
    38     State* m_pState;
    39 };
    40 
    41 int main() {
    42     State* pStateA = new ConcreteStateA();
    43     State* pStateB = new ConcreteStateB();
    44     Context* pContext = new Context(pStateA);
    45     pContext->Request();
    46     pContext->ChangState(pStateB);
    47     pContext->Request();
    48 
    49     delete pContext;
    50     delete pStateB;
    51     delete pStateA;
    52 
    53     return 0;
    54 }

    总结

    状态模式是利用多态的动态绑定特性消除了if-else的分支结构,将对象的状态与对应状态下的行为分离开来,每一个状态对应一个类,一个类集中管理一个状态,在多状态的情况下,简化程序的结构,易于扩展。
    参考:

    C++设计模式——状态模式

  • 相关阅读:
    111.浮动初识 Walker
    105.灰度和对比度 Walker
    102.表格属性 Walker
    POJ 1321 棋盘问题
    HDU 1106 排序 题解
    HDU 1240 Asteroids! 解题报告
    HDU 1372 Knight Moves
    HDU 1253 胜利大逃亡
    HDU 1231:最大连续子序列 解题报告
    POJ 2251 Dungeon Master
  • 原文地址:https://www.cnblogs.com/y4247464/p/15502497.html
Copyright © 2020-2023  润新知