设计模式的理解:状态模式(State) 和备忘录模式(Memento)
一、状态模式
状态模式,允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。它的实现方式和策略模式相似,目的都是对if...else语句进行优化,只不过,策略模式通过外部传入枚举、条件来决定选择哪一种操作方式。策略模式中的枚举、条件相当于状态模式中的状态。状态不需要由外部传入,而是随着自身的操作来自动地变化。

例如类Context 包含以下的流程图,context 有两个方法run 和fallback,四种状态,例如当状态Ready执行一次run操作状态变成了d式,允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。它的实现方式和策略模式相似,目的都是对if...else语句进行优化,只不过,策略模式通过外部传入枚举、条件来决定选择哪一种操作方式。策略模式中的枚举、条件相当于状态模式中的状态。状态不需要由外部传入,而是随着自身的操作来自动地变化。
例如类Context 包含以下的流程图,context 有两个方法run 和fallback,四种状态,例如当状态Ready执行一次run操作状态变成了executing,当再执行run时就变成了完成状态,如果执行fallback就变成了hangup状态。

本例目标是为了展示 2*100 的计算和输出过程。
方法一
enum State{Ready,Executing,Finish,Hangup
}class Context{State state;int result;public:void run(){if(state == Ready){result = 2;state = Executing;}else if(state == Executing){result *=100;state =Finish;}else if(state == Finish){cout<<"result:"<
当操作方法发生需求变更时,方法一代码这样写影响范围就会覆盖整个流程,代码不易维护,不易扩展。如果增加状态,那么枚举要新增,run方法和fallback方法也要跟者新增,代码会变得越来越臃肿。
方法二:利用状态模式,把枚举变成类对象
enum State{Ready,Executing,Finish,Hangup
}
/********状态类,可用单例模式进行优化***********/
class IState{virtual State oprationRun(Context *)=0;virtual State oprationFallback(Context *)=0;
};
class ReadyState:public IState{
public:virtual State oprationRun(Context * context){context->result=2;return Executing;}virtual State oprationFallback(Context * context){context->result=0;return Ready;}
};
class ExecutingState:public IState{
public:virtual State oprationRun(Context * context){context->result *=100;return Finish;}virtual State oprationFallback(Context * context){return Hangup;}
};
class FinishState:public IState{
public:virtual State oprationRun(Context * context){cout<<"result:"<< context->result;context->result =0;return Ready;}virtual State oprationFallback(Context * context){context->result /=100;return Executing;}
};
class HangupState:public IState{
public:virtual State oprationRun(Context * context){return Executing;}virtual State oprationFallback(Context * context){context->result=2;return Ready;}
};/*********Context自动地完成操作******************/
class Context{State state; //状态属性,这个属性变化,操作也会动态地变化IState * iState; //状态对象int result;
private:
void initIState(){switch(state){case Ready: iState =new ReadyState(); break;case Executing:iState =new ExecutingState(); break;case Finish: iState =new FinishState(); break;case Hangup: iState =new HangupState(); break;Default:....ERROR....}
}public:Context(){state =Ready;result =0;}void run(){initIState();state =iState->oprationRun(this);}void fallback(){initIState();state =iState->oprationFallback(this);}
}
这样的好处就是当变更状态内部操作时,不需要改动Context方法。当新增一个状态时,只需要新增一个状态类和一个映射就可以,不需要变动其他状态方法。这样编码结构清晰,误操作的可能变小,变得更容易维护。
最后调用过程
void main(){Context context; //result =0 ,状态为Readycontext.run(); //result =2 ,状态从Ready变成Executing;context.run(); //result =200 ,状态从Executing变成finish;context.run(); //输出 200 ,状态从finish变成Ready; result =0
}
二、备忘录模式
备忘录模式,在不破坏封装性的前提下,捕获对象内部的状态,并将者着状态放在外部进行保存(比如文件,数据库)。方便以后对象恢复到原先的状态。相当于游戏的存档。
在模式中,具体实现的方式就是新增一个类,用来存储原先对象重要的属性。
继续按照上述例子,新增备忘录类和get/set备忘录方法
enum State{Ready,Executing,Finish,Hangup
}
/********状态类,可用单例模式进行优化***********/
class IState{virtual State oprationRun(Context *)=0;virtual State oprationFallback(Context *)=0;
};
class ReadyState:public IState{
public:virtual State oprationRun(Context * context){context->result=2;return Executing;}virtual State oprationFallback(Context * context){context->result=0;return Ready;}
};
class ExecutingState:public IState{
public:virtual State oprationRun(Context * context){context->result *=100;return Finish;}virtual State oprationFallback(Context * context){return Hangup;}
};
class FinishState:public IState{
public:virtual State oprationRun(Context * context){cout<<"result:"<< context->result;context->result =0;return Ready;}virtual State oprationFallback(Context * context){context->result /=100;return Executing;}
};
class HangupState:public IState{
public:virtual State oprationRun(Context * context){return Executing;}virtual State oprationFallback(Context * context){context->result=2;return Ready;}
};/*********Context自动地完成操作******************/
class Context{State state; //状态属性,这个属性变化,操作也会动态地变化IState * iState; //状态对象int result;
private:
void initIState(){switch(state){case Ready: iState =new ReadyState(); break;case Executing:iState =new ExecutingState(); break;case Finish: iState =new FinishState(); break;case Hangup: iState =new HangupState(); break;Default:....ERROR....}
}public:Context(){state =Ready;result =0;}void run(){initIState();state =iState->oprationRun(this);}void fallback(){initIState();state =iState->oprationFallback(this);}/****创建存档和读取存档*****/ContextMemento createMemento(){return ContextMemento (state,result);}void setMemento(ContextMemento& cm){state = cm.oldstate;result = cm.oldresult;}
}/**********备忘录对象************/
class ContextMemento{
public: State oldstate; //状态属性,这个属性变化,操作也会动态地变化int oldresult;ContextMemento (State s, int r){oldstate= s; oldresult=r;}
}
void main(){Context context; //result =0 ,状态为Readycontext.run(); //result =2 ,状态从Ready变成Executing;ContextMemento contextMemento = context.createMemento();context.run(); //result =200 ,状态从Executing变成finish;context.setMemento(contextMemento ); //result =2 状态为 Executingcontext.run(); //result =200 ,状态从Executing变成finish;context.run();//输出 200 ,状态从finish变成Ready; result =0
}
备忘录的目的就是为了存档,现如今,储存/读取对象有更方便的方式。备忘录模式在如今有些过时。更有效的方式可以替代备忘录模式,例如对象序列化,对象编码等。但是备忘录的思想还是没变:
1)不破坏原对象的封装性
2) 获取原对象重要的属性,并对这些属性进行隐藏
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
