总结7.状态变化:状态模式,备忘录
声明:本栏目的 [A] 系列的学习笔记,学习对象为 B 站授课视频 C++设计模式(李建忠),参考教材为《设计模式:可复用面向对象软件的基础》。本栏目 [A] 系列文章中的图件和笔记,部份来自上述资源。
从封装变化角度对模式分类!:
- 组件协作
- 单一职责
- 对象创建
- 对象性能
- 接口隔离
- 状态变化
在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?“状态变化”模式为这一问题提出了解决方案。
典型模式
• 状态模式 State
• 备忘录模式 Memento- 数据结构
- 行为变化
- 领域问题
状态模式 State
- 定义:允许一个对象在其内部状态改变时改变它的行为,从而使对象看起来似乎修改了其行为。
- 应用举例:做一个网络的应用,根据网络的状态(open,close,connect)来做不同的操作,且做完之后就切换状态。
- 一般不考虑设计原则不使用设计模式的 代码可以这么写:
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(){
//***
}
};
- 分析:以上代码,用枚举变量来表示网络状态的类型,NetworkProcessor 中变量 state 表示当前网络状态,operation1,2,3 是三个根据不同网络状态做出不同行为然后切换网络状态state的成员函数,函数中用 if else 做状态判断。这样的设计在 策略模式 中就谈过,一旦有新增的网络状态,修改就很 麻烦。不符合对修改封闭,对扩展开放的原则。
- 在类的方法中出现 多个 if else 就值得注意了,这可能需要更好的设计。如下
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();
}
};
class CloseState:public NetworkState{ }
//...类似上面的OpenState
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;
//...
}
};
- 分析:首先提出网络状态抽象基类,基类中有 operation1,2,3 这三个根据不同网络状态做出不同行为然后切换网络状态state的成员函数,成员变量 pNext 记录切换后的状态。打开,关闭,连接这三个网络状态继承上述基类,且这个类在系统中只需存在一个对象即可,所以用单件模式。operation函数在执行对应操作后,给 pNext 赋值新的网络状态。
- NetworkProcessor 将网络状态类作为成员类 pState,使用其功能,三个operation函数中调用pState的三个对应函数,然后将 pState 赋值新的网络状态对象。这样设计,做到了网络状态发生变化时相应的改变行为。
- 这样设计,以后改变 一般只需要增加新的子类即可。无需改变已有的代码。
备忘录模式 Memento
- 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
class Memento
{
string state;
//..
public:
Memento(const string & s) : state(s) {}
string getState() const { return state; }
void setState(const string & s) { state = s; }
};
class Originator
{
string state;
//....
public:
Originator() {}
Memento createMomento() {
Memento m(state);
return m;
}
void setMomento(const Memento & m) {
state = m.getState();
}
};
int main() {
Originator orginator;
//捕获对象状态,存储到备忘录
Memento mem = orginator.createMomento();
//... 改变orginator状态
//从备忘录中恢复
orginator.setMomento(memento);
}
- 使用 Memento 来存储 Originator 的状态,之后在必要的时间点,再把以前存储的状态提供给 Originator,让其恢复到特定历史时间点的状态。
- 此模式现在而言有些过时了。