设计模式(22)状态模式

状态模式简介

在实际开发中,通常会遇到有多个状态的对象,这个对象在不同的状态下,都会有不同的行为。

状态模式的重点在于状态转换,很多时候,对于一个对象的状态,我们都是让这个对象包含一个状态的属性,这个状态属性记录着对象的具体状态,根据状态的不同使用分支结构来执行不同的功能;就像上面说的,类中存在大量的结构类似的分支语句,变得难以维护和理解。

状态模式消除了分支语句,就像工厂模式消除了简单工厂模式的分支语句一样,将状态处理分散到各个状态子类中去,每个子类集中处理一种状态,这样就使得状态的处理和转换清晰明确。状态模式将一个对象的状态从对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化。对于客户端而言,无需关心对象转态的转换以及对象所处的当前状态,无论处于何种状态的对象,客户端都可以一致处理。

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

状态模式结构

在这里插入图片描述
状态模式引入了抽象层,具有抽象状态类和具体状态类,还包括一个上下文境类:

  • Context(上下文类):是拥有多种状态的对象。上下文类的状态存在多样性,并且在不同的状态下,对象表现出不同的行为。在上下文类中,维护了一个抽象状态类的实例。
  • State(抽象状态类):声明了一个接口,用于封装与在上下文类中的一个特定状态相关的行为,在子类中实现在各种不同状态对应的方法。不同的子类可能存在不同的实现方法,相同的方法可以写在抽象状态类中。
  • ConcreteState(具体状态类):实现具体状态下的方法,每一个具体状态类对应一个具体的状态。

上下文中维护了一个状态类的指针或者引用,可以由上下文类来觉得具体实例化为哪一个具体的状态对象,也可以由具体的状态类来决定转换为哪一个实例,所以,上下文类和状态类之间存在依赖甚至相互引用的关系。

状态模式代码实例

#include <iostream>

using namespace std;

class Context;

class State
{
    
    
public:
  virtual void Handle(Context *pContext) = 0;
};

class ConcreteStateA : public State
{
    
    
public:
  virtual void Handle(Context *pContext)
  {
    
    
    cout << "I am concretestateA." << endl;
  }
};

class ConcreteStateB : public State
{
    
    
public:
  virtual void Handle(Context *pContext)
  {
    
    
    cout << "I am concretestateB." << endl;
  }
};

class Context
{
    
    
public:
  Context(State *pState) : m_pState(pState) {
    
    }

  void Request()
  {
    
    
    if (m_pState)
    {
    
    
      m_pState->Handle(this);
    }
  }

  void ChangeState(State *pState)
  {
    
    
    m_pState = pState;
  }

private:
  State *m_pState;
};

int main()
{
    
    
  State *pStateA = new ConcreteStateA();
  State *pStateB = new ConcreteStateB();
  
  Context *pContext = new Context(pStateA);

  pContext->Request();

  pContext->ChangeState(pStateB);
  pContext->Request();

  delete pContext;
  delete pStateB;
  delete pStateA;
}

状态模式总结

优点:

  • 状态模式封装了状态转换的规则,只给外界暴露了统一的接口,客户端可以无差别地调用该接口(如上述实例的客户端代码)
  • 状态模式将所有与具体状态有关的行为放到一个类(具体状态类)中,只需要注入(依赖)不同的状态类对象到上下文类中,即可使上下文中拥有不同的行为

缺点:

  • 状态模式增加了系统中类的个数(不同的具体状态类)
  • 结构相对复杂(如前述实例的UML图),代码逻辑也较复杂
  • 如果要增加新的状态,需要修改负责状态转换的代码,不符合开闭原则(如上述实例,如果增加了一个中间级别,是不是得修改很多状态转换的逻辑?)

适用环境:

  • 对象的行为根据它的状态的改变而不同
  • 代码中含有大量与对象状态有关的判断逻辑(if……else……或switch……case……)

Guess you like

Origin blog.csdn.net/qq_24649627/article/details/115488954