设计模式 ——状态模式

“状态变化”模式

在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?“状态变化”模式应运而生。
典型模式 :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\n"; }
16 };
17 
18 class ConcreteStateB : public State {
19    public:
20     virtual void Handle(Context* pContext) { cout << "I am concreteStateB\n"; }
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++设计模式——状态模式

posted @ 2021-11-03 10:22  朱果果  阅读(165)  评论(0编辑  收藏  举报