【GeekBand】C++设计模式笔记18_State_状态模式
1. “状态变化” 模式
- 在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?“状态变化” 模式为这一问题提供了一种解决方案。
- 典型模式
- State
- Memento
2. State 状态模式
2.1 动机(Motivation)
- 在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。
- 如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?
2.2 模式定义
允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。
——《设计模式》GoF
2.3 实例代码
2.3.1 非State模式
enum NetworkState
{
Network_Open,
Network_Close,
Network_Connect,
};
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;
}
}
public 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;
}
}
public void Operation3() {
}
};
非State模式代码中的类方法中充斥着大量的if分支语句来判断状态的值,从而采取对应的操作,显得很臃肿;而且,当添加一个新状态时,需要在所有的if条件判断语句中添加新的分支。
2.3.2 State模式
// 状态的抽象类
class NetworkState {
public:
NetworkState* pNext; // 下一个状态值
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();
}
};
// 代码类似OpenState
class CloseState: 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;
//...
}
};
State模式代码中去除了大量的if条件判断分支,将每个状态用一个单独的状态子类来表示,且将与具体状态相关的操作放在子类中。在实际应用中,接口保持不变,利用多态特性,根据状态的真实值从而调用对应的方法。
2.4 结构(Structure)
2.5 要点总结
- State模式将所有与一个特定状态相关的行为都放入一个State的子类对象中,在对象状态切换时,切换相应的对象;但同时维持State的接口,这样实现了具体操作与状态切换之间的解耦。
- 为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子的——即要么彻底转换过来,要么不转换。
- 如果State对象没有实例变量,那么各个上下文可以共享同一个State对象,从而节省对象开销。