设计模式-状态模式

1 状态模式

  • 在软件构建过程中,某些对象的状态如果改变,其行为也会随之改变,比如文档处于只读状态,其支持的行为和读写状态支持的行为可能完全不同
  • 允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为
  • 用类表示状态,通过切换类改变对象状态
  • 跟Strategy模式很像,区别是:状态模式采用单例模式,抽象类包含指向下一个状态的指针

2 问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
enum NetworkState{
Network_Open,
Network_Close,
Network_Connect
// 假设未来有新状态:Network_Wait,怎么办?
};

class NetworkProcessor{
NetworkState state;

public:
void Operation1(){
if (state == Network_Open){
//**********
state = Network_Close;
}
else if (state == Network_Close){
//..........
state = Network_Connect;
}
else if (state == Network_Connect){
//$$$$$$$$$$
state = Network_Open;
}
}

void Operation2(){
if (state == Network_Open){
//**********
state = Network_Connect;
}
else if (state == Network_Close){
//..........
state = Network_Open;
}
else if (state == Network_Connect){
//$$$$$$$$$$
state = Network_Close;
}
}

void Operation3(){
// ...
}
};

3 状态v1

状态模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// 把以前的枚举类型转换为抽象基类
// 再把以前的所有操作,作为状态对象的行为
// 最后再塞一个状态对像的指针
class NetworkState{
protected:
NetworkState* pNext; // next指针
public:
virtual void Operation1()=0;
virtual void Operation2()=0;
virtual void Operation3()=0;

virtual ~NetworkState(){}
};


class OpenState: public NetworkState{
static NetworkState* m_instance; // 存放该类唯一实例的指针
public:
static NetworkState* getInstance(){ // 单例模式
if (m_instance == nullptr) {
m_instance = new OpenState();
}
return m_instance;
}

void Operation1(){
// **********
pNext = CloseState::getInstance();
}

void Operation2(){
// ..........
pNext = ConnectState::getInstance();
}

void Operation3(){
// $$$$$$$$$$
pNext = OpenState::getInstance();
}
};

class CloseState: public NetworkState{
// ...
}

class ConnectionState: public NetworkState{
// ...
}

// 可以非常方便的添加扩展
class WaitState: public NetworkState{
// ...
}


class NetworkProcessor{
NetworkState* pState;

public:
NetworkProcessor(NetworkState* pState){ // 构造函数
this->pState = pState;
}

void Operation1(){
// ...
pState->Operation1(); // 多态调用
pState = pState->pNext; // 精妙
// ...
}

void Operation2(){
// ...
pState->Operation2(); // 多态调用
pState = pState->pNext; // 精妙
// ...
}

void Operation3(){
// ...
pState->Operation3(); // 多态调用
pState = pState->pNext; // 精妙
// ...
}
};

4 状态v2(可执行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
class IContext;
class IState { // 某版直接包含IContext指针
public:
virtual ~IState() {}
virtual void doColock(IContext *ctx, int hour) = 0;
virtual void doUse(IContext *ctx) = 0;
virtual void doAlarm(IContext *ctx) = 0;
virtual void doPhone(IContext *ctx) = 0;
};

class IContext {
public:
enum class ActionType {
Use,
Alarm,
Phone
};
virtual ~IContext() {}
virtual void doAction(ActionType actionType) = 0;
virtual void setClock(int hour) = 0;
virtual void stateChange(IState *state) = 0;
virtual void callSecurityCenter(const std::string &msg) = 0;
virtual void recoderLog(const std::string &msg) = 0;
};

class DayState : public IState{
public:
static DayState &GetInstance(){
static DayState s;
return s;
}
virtual void doColock(IContext *ctx, int hour) override;
virtual void doUse(IContext *ctx) override{
ctx->recoderLog("Day use ");
}
virtual void doAlarm(IContext *ctx) override{
ctx->callSecurityCenter("Day alarm");
}
virtual void doPhone(IContext *ctx) override{
ctx->callSecurityCenter("Day phone");
}

~DayState() = default;
DayState(const DayState &) = delete;
DayState(DayState &&) = delete;
DayState &operator=(const DayState &) = delete;
DayState &operator=(DayState &&) = delete;

protected:
DayState() {}
};

class NightState : public IState {
public:
static NightState &GetInstance() {
static NightState s;
return s;
}
virtual void doColock(IContext *ctx, int hour) override;
virtual void doUse(IContext *ctx) override {
ctx->callSecurityCenter("Night use ");
}
virtual void doAlarm(IContext *ctx) override {
ctx->callSecurityCenter("Night alarm");
}
virtual void doPhone(IContext *ctx) override {
ctx->recoderLog("Night phone");
}

~NightState() = default;

NightState(const NightState &) = delete;
NightState(NightState &&) = delete;
NightState &operator=(const NightState &) = delete;
NightState &operator=(NightState &&) = delete;

protected:
NightState() {}
};

void DayState::doColock(IContext *ctx, int hour) {
if (hour < 9 || hour >= 17) {
ctx->stateChange(&NightState::GetInstance());
}
}

void NightState::doColock(IContext *ctx, int hour) {
if (hour >= 9 && hour < 17) {
ctx->stateChange(&DayState::GetInstance());
}
}

class SafeFrame : public IContext{
public:
SafeFrame();
virtual void setClock(int hour) override;
virtual void doAction(ActionType actionType) override;
virtual void stateChange(IState *state) override;
virtual void callSecurityCenter(const std::string &msg) override;
virtual void recoderLog(const std::string &msg) override;

private:
IState *m_state;
};

SafeFrame::SafeFrame() : m_state(&DayState::GetInstance()) {} // 初始化白天

void SafeFrame::setClock(int hour){
std::cout << "now timw is " << hour << std::endl;
m_state->doColock(this, hour);
}

void SafeFrame::doAction(ActionType actionType){
switch (actionType){
case ActionType::Alarm:
m_state->doAlarm(this);
break;
case ActionType::Phone:
m_state->doPhone(this);
break;
case ActionType::Use:
default:
m_state->doUse(this);
break;
}
}

void SafeFrame::stateChange(IState *state){
std::cout << __FUNCTION__ << std::endl;
m_state = state;
}

void SafeFrame::callSecurityCenter(const std::string &msg){
std::cout << __FUNCTION__ << " " << msg << std::endl;
}

void SafeFrame::recoderLog(const std::string &msg){
std::cout << __FUNCTION__ << " " << msg << std::endl;
}

int main() {
IContext *ctx = new SafeFrame;
for (int i = 0; i < 24; ++i) {
ctx->setClock(i);
ctx->doAction(IContext::ActionType::Use);
ctx->doAction(IContext::ActionType::Phone);
ctx->doAction(IContext::ActionType::Alarm);
}
delete ctx;
return 0;
}

5 总结

  • State模式将所有与一个特定状态相关的行为都放入一个State的子类对象中,在对象状态切换时,切换相应的对象;但同时维持State的接口,这样实现了具体操作与状态转换之间的解耦。
  • 为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的——即要么彻底转换过来,要么不转换。
  • 如果State对象没有实例变量,那么各个上下文可以共享同一个State对象,从而节省对象开销。

6 参考