设计模式之状态模式
状态模式,当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了类本身。状态模式主要解决的时当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。其UML图如下:
在以上UML图中,Context中有一个状态的引用(C++中是指针),当该状态发生变化时,Context中的状态不同,响应的操作会调用不同对象的Handle方法。而在ConcreteState中会判断当前状态是否与自身状态相同(每一个状态一个类),如果相同则调用自身的Handle方法,如果不同则修改Context中State的引用,并调用相关的Handle方法。所以通用的状态模式的UML图是有问题的,其实State类是依赖于Context类的。也就是说其UML图应该是下图:
示例代码如下:
1 // StateModel.h文件
2 #pragma once
3 #include <iostream>
4
5 class Context;
6
7 class State
8 {
9 public:
10 virtual void Operation(Context *pContext) = 0;
11 };
12
13 class Context
14 {
15 private:
16 State * m_state;
17 public:
18 Context(State * p)
19 {
20 m_state = p;
21 }
22 ~Context()
23 {
24 if (nullptr != m_state)
25 delete m_state;
26 }
27 void SomeOperation()
28 {
29 m_state->Operation(this);
30 }
31 void setState(State * p)
32 {
33 delete m_state;
34 m_state = p;
35 }
36 };
37
38 class ConcreteStateA : public State
39 {
40 public:
41 void Operation(Context * pContext);
42 };
43
44 class ConcreteStateB : public State
45 {
46 void Operation(Context * pContext)
47 {
48 std::cout << "OperationB" << std::endl;
49 // 这里有一个要更换状态,主要看实际需求
50 pContext->setState(new ConcreteStateA());
51 }
52 };
53
54 void ConcreteStateA::Operation(Context * pContext)
55 {
56 std::cout << "OperationA" << std::endl;
57 // 这里有一个要更换状态,主要看实际需求
58 pContext->setState(new ConcreteStateB());
59 }
测试代码如下:
1 #include <iostream>
2 #include "StateModel.h"
3
4 int main()
5 {
6 using namespace std;
7 // 状态模式
8 Context *p = new Context(new ConcreteStateA());
9 p->SomeOperation();
10 p->SomeOperation();
11 delete p;
12 getchar();
13 return 0;
14 }
测试结果如下图:
还有一个问题,就是状态模式的UML类图和策略模式的UML类图非常的相似。那么我们就很有必要区分一下这两个模式。其实也很好区分,这两者的主要区别并不是类结构图上的不同,更多的则是类的实现的不同。策略模式测中与不同情况下调用不同的算法。而状态模式侧重于根据自身状态的不同做出不同的响应,而且状态模式中最重要的一点是状态可以被状态类更改。比如当前状态做完相应的工作后可能会把状态修改为另一个状态。而这个区别也是UML图中的唯一一个不同所造成的区别。因为状态模式中的State是依赖于Context的。