解析C++编程中如何使用设计模式中的状态模式结构

 更新时间:2016年03月16日 11:30:16   作者:cly  
这篇文章主要介绍了如何在C++编程中适用设计模式中的状态模式结构,状态模式强调将特定状态相关的逻辑分散到一些类的状态类中,需要的朋友可以参考下

作用:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

UML图如下:

2016316112712572.png (609×389)

State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为。
ConcreteState类,具体状态,每一个子类实现一个与Context的一个状态相关的行为。
Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态。

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。

状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。

将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。

可以消除庞大的条件分支语句。状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖。

当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式。
另外如果业务需求某项业务有多个状态,通常都是一些枚举常量,状态的变化都是依靠大量的多分支判断语句来实现,此时应该考虑将每一种业务状态定义为一个State的子类。这样这些对象就可以不依赖于其他对象儿独立变化了。

实例代码如下:

State.h#ifndef _STATE_H_

#define _STATE_H_

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

class ConcreteStateA : public State
{
public:
  ConcreteStateA();
  ~ConcreteStateA();
  virtual void Handle(Context* pContext);
protected:
private:
};

class ConcreteStateB : public State
{
public:
  ConcreteStateB();
  ~ConcreteStateB();
  virtual void Handle(Context* pContext);
protected:
private:
};

class ConcreteStateC : public State
{
public:
  ConcreteStateC();
  ~ConcreteStateC();
  virtual void Handle(Context* pContext);
protected:
private:
};

class Context
{
public:
  Context(State* pState);
  ~Context();
  void Request();
  void ChangeState(State* pState);
protected:
private:
  State* _state;
};


#endif


State.cpp

#include "State.h"
#include <iostream>

using namespace std;

State::State()
{}

State::~State()
{}

ConcreteStateA::ConcreteStateA()
{}

ConcreteStateA::~ConcreteStateA()
{}

//执行该状态的行为并改变状态
void ConcreteStateA::Handle(Context* pContext)
{
  cout << "ConcreteStateA" << endl;
  pContext->ChangeState(new ConcreteStateB());
}

ConcreteStateB::ConcreteStateB()
{}

ConcreteStateB::~ConcreteStateB()
{}

//执行该状态的行为并改变状态
void ConcreteStateB::Handle(Context* pContext)
{
  cout << "ConcreteStateB" << endl;
  pContext->ChangeState(new ConcreteStateC());
}

ConcreteStateC::ConcreteStateC()
{}

ConcreteStateC::~ConcreteStateC()
{}

//执行该状态的行为并改变状态
void ConcreteStateC::Handle(Context* pContext)
{
  cout << "ConcreteStateC" << endl;
  pContext->ChangeState(new ConcreteStateA());
}

//定义_state的初始状态
Context::Context(State* pState)
{
  this->_state = pState;
}

Context::~Context()
{}

//对请求做处理,并设置下一状态
void Context::Request()
{
  if(NULL != this->_state)
  {
    this->_state->Handle(this);
  }
}

//改变状态
void Context::ChangeState(State* pState)
{
  this->_state = pState;
}

main.cpp
#include "State.h"

int main()
{
  State* pState = new ConcreteStateA();
  Context* pContext = new Context(pState);
  pContext->Request();
  pContext->Request();
  pContext->Request();
  pContext->Request();
  pContext->Request();
  return 0;
}

总结

对于状态模式,很多情况下和策略模式看起来极为相似。实际上它们都是为了解决具体子类实现抽象接口的实现异构问题而存在的(封装变化),但是它们的侧重各不相同。而针对算法的异构问题,模板方法模式通过继承的方式来改变一部分算法实现(原子操作在不同具体子类中可以有不同实现),策略模式则通过组合的方式来改变整个算法(可动态替换),而状态模式则强调的是针对不同的状态对象可以有不同的响应。因此状态模式实际上强调的状态的概念,并且强调对状态转换的逻辑封装,即对象可能处于不同的状态下,而各个状态在响应了该状态的实现后可能会动态转到另一个状态,而这个转变我们不希望 Context 的参与(Context 不必维护这个转换)。状态机在编译原理的 DFA/NDFA 中很常见,针对一个输入字符和已有串,DFA/NDFA 可能会转换到另外一个状态。

因此对于状态模式有以下几个关键点:

1. 状态模式会处理算法的不同,但是更加关注的是状态的改变。并且对于状态的转变逻辑一般会放在 State 子类中实现。而对于不同状态的处理则可以放在 Context 类中,State 子类保存一个指向 Context 的引用(实际上往往传递一个指向 Context 的指针即可,而不必在 State 子类真正保存一个引用),以调用这些实现。当然放在 State 子类中实现也无可厚非,不过为了突出重点,使用前一种方式实现更能说明问题。当然在实际开发中,完全可以不受这个制约。

2.在具体实现过程中,对状态的改变我们会在 Context 类中实现(因为Context 才有 State 的概念),而在 State 子类中的状态转变逻辑实现则通过调用这个实现来达到目的。当然为了不让这个改变状态的接口暴露给普通客户程序员,我们将 Context 中这个接口声明为 private,而在将State 类声明为 Context 的 friend 类,并且将 State 子类中状态改变逻辑实现声明为 Protected,不让普通客户程序员调用。具体请参考示例代码部分。

相关文章

  • 基于C语言实现五子棋游戏完整实例代码

    基于C语言实现五子棋游戏完整实例代码

    这篇文章主要介绍了基于C语言实现五子棋游戏完整实例代码,相信对于学习游戏开发的朋友会有一定的帮助与借鉴价值,需要的朋友可以参考下
    2014-08-08
  • C++之编写高效Makefile文件最佳方法

    C++之编写高效Makefile文件最佳方法

    在软件开发过程中,Makefile是一个非常重要的工具,它可以帮助我们自动化构建、编译、测试和部署,然而,编写高效的Makefile文件并不是一件容易的事情。在本文中,我们将讨论如何编写高效的Makefile文件,以提高开发效率和产品质量,需要的朋友可以参考下
    2023-05-05
  • 四叉树有损位图压缩处理程序示例

    四叉树有损位图压缩处理程序示例

    这篇文章主要介绍了四叉树有损位图压缩处理程序示例,可以对24位图进行压缩,应用于windows平台,需要的朋友可以参考下
    2014-04-04
  • C语言MFC基础之计算器详解

    C语言MFC基础之计算器详解

    这篇文章主要为大家介绍了MFC实现简单的计算器,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-08-08
  • C语言版五子棋游戏的实现代码

    C语言版五子棋游戏的实现代码

    这篇文章主要为大家详细介绍了C语言版五子棋游戏的实现代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • C++实现俄罗斯方块(linux版本)

    C++实现俄罗斯方块(linux版本)

    这篇文章主要为大家详细介绍了linux版本C++实现俄罗斯方块,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • 一起来学习C++中类的this指针以使用

    一起来学习C++中类的this指针以使用

    这篇文章主要为大家详细介绍了C++中类的this指针以使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • C++中的异常实例详解

    C++中的异常实例详解

    异常处理是C++的一项语言机制,用于在程序中处理异常事件,下面这篇文章主要给大家介绍了关于C++中异常的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-02-02
  • C++之Boost::array用法简介

    C++之Boost::array用法简介

    这篇文章主要介绍了C++之Boost::array用法简介,较为详细的分析了Boost::array中的常见用法,并用实例的形式予以总结归纳,需要的朋友可以参考下
    2014-10-10
  • C语言实现交换排序算法(冒泡,快速排序)的示例代码

    C语言实现交换排序算法(冒泡,快速排序)的示例代码

    这篇文章主要为大家详细介绍了如何利用C语言实现交换排序算法(冒泡排序、快速排序),文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2022-07-07

最新评论