状态变化模式
比如我们有个网络应用,该应用会根据网络的状态进行一些行为上的调整,如下代码所示
- 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;
- }
- }
-
- 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(){
- // ...
- }
- };
结合上面代码和前面的动机对比理解:
对象的状态如果改变,其行为也会随之而发生改变:Operation1中的if else就已经很清楚的表明了Operation1是根据你的状态不同,而行为不一样,但是在这个过程中它还会改变它的状态
上面代码有什么问题,有前面学习印象的同学,会感觉这个问题似曾相识,这个很像是策略模式里面解决的问题,很多if else的bad Smell,上面出现的很多If else是有关业务状态,策略模式就已经告诉我们,对于这种情况,我们要问个为什么?
上面代码中的枚举类型以后会不会有其他类型出现呢?如果添加了其他的状态,那我之前的代码应该怎么修改,必然是往里面继续添加else if,然后还要梳理新添加的状态和当前已经存在状态的关系,这明显违背了开闭原则
我们首先遵从策略模式里面的类似方式,试下是否可行,我们先提抽象基类
- // 这里其实就是将前面的枚举进行类型化的
- class NetworkState{
- public:
- NetworkState *pNext;
- virtual void Operation1() = 0;
- virtual void Operation2() = 0;
- virtual void Operation3() = 0;
-
- NetworkState(){}
- virtual ~NetworkState(){}
- };
-
-
- // 这里的代码其实就是将判断当前时候是open态的那部分逻辑抽离成了类,即Open态的类
- 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(){
-
- // ....这段省略逻辑其实就是前面
- // void Operation1(){
- // if (state == Network_Open){
- // 中省略的逻辑的逻辑
-
- pNext = CloseState::getInstance();
- }
-
- void Operation2(){
- // ...
- pNext = ConnectState::getInstance();
- }
-
- void Operation3(){
- // ...
- }
- };
-
- // 下面两个类和前面这个类似
- class CloseState : public NetworkState{
-
- };
-
- class ConnectState : public NetworkState{
-
- };
-
- // 网络应用这一层,塞的就不是一个枚举了,而是一个真正的状态对象
- class NetworkProcessor{
- NetworkState *pState; // 1. 其实这里,和前面的结果是一样的,只是调用的方法变了而已
- public:
- NetworkProcessor(NetworkState *pState){
- this->pState = pState;
- }
-
- void Operation1(){
- // ..
- pState->Operation1(); // 2. 再看这句话,其实虚函数的本质就是运行时的if else即,如果pState这个指针指向的是open态,那么就会调用Open态的Operation1
- pState = pState->pNext; // 3. 执行完后,就将它的状态修改为它的下一个状态,这个下一个状态是当前状态对象里面决定的
- // ...
- }
-
- void Operation2(){
- // ..
- pState->Operation2();
- pState = pState->pNext;
- // ...
- }
-
- void Operation3(){
- // ..
- pState->Operation3();
- pState = pState->pNext;
- // ...
- }
这样做了之后好处是什么,其实和策略模式好处异曲同工,当我们状态增加的时候,其实我们只要增加一个类就可以了,比如增加了一个wait状态,只需要增加一个类似下面的类,并且要在这个类里面维护自己的下一个状态,和OpenState一样,像NetworkProcessor这个类完全不需要修改
- class WaitState : public NetworkState{
- };
允许一个对象在其内部状态改变的时候改变它的行为(其实里里面使用的是多态,即前面代码中NetworkProcessor中维护的NetworkState *pState;)。从而使对象看起来似乎修改了其行为。
------《设计模式》GOF
State里面一般是多个行为而不是一个Handle(),当然也可以是一个行为,看起来一个行为的时候和策略模式没有什么两样
(第一版代码各个操作中夹杂着各种状态的切换,很乱很杂,但是我们最后的版本,一个状态只需要关系各个操作之后的下一个状态是什么就好了,比如:operation1之后的状态是什么,2之后的状态是什么,3之后的状态是什么,就很清晰)