状态模式的场景应用

现在遇到了这样一个场景:要将一系列操作自动化,其中涉及到一些状态以及状态的转移。状态有4种:初始状态0,第一步A,第二步B,第三步C。其中这几个状态间的转移关系就略去了,抽象出来是这样的:无论从哪种状态转移到目标状态,做出的行为都是表示“到目标状态”所做的行为,即与上一步状态无关,只与目标状态有关。故使用状态模式实现。简单说明问题的代码如下:

状态管理:

 1 public class StateManager {
 2     private State state;
 3     private StateManager() {}
 4     public StateManager(State state) {this.state = state;}
 5     public StateManager(String state) {... // 根据状态码初始化云云}
 6     public State getState() {return state;}
 7     public void setState(State state) {this.state = state;}
 8     public void to0() {state.to0(this);}
 9     public void toA() {state.toA(this);}
10     public void toB() {state.toB(this);}
11     public void toC() {state.toC(this);}
12 }

状态接口:

1 public interface State {
2     void to0(StateManager sm);
3     void toA(StateManager sm);
4     void toB(StateManager sm);
5     void toC(StateManager sm);
6 }

抽象父类:

1 public abstract class AbstractState implement State {
2     public void to0(StateManager sm) { throw new UnsupportedOperationException();}
3     public void toA(StateManager sm) { throw new UnsupportedOperationException();}
4     public void toB(StateManager sm) { throw new UnsupportedOperationException();}
5     public void toC(StateManager sm) { throw new UnsupportedOperationException();}
6 }

具体子类:

 1 public class State0 extends AbstractState {
 2     public void toA(StateManager sm) { print("toA");sm.setState(new StateA()); } // 允许转移到A
 3 }
 4 
 5 public class StateA extends AbstractState {
 6     public void to0(StateManager sm) { print("to0");sm.setState(new State0()); } // 允许重置
 7     public void toB(StateManager sm) { print("toB");sm.setState(new StateB()); } // 允许转移到B
 8     public void toC(StateManager sm) { print("toC");sm.setState(new StateC()); } // 允许转移到C
 9 }
10 
11 public class StateB extends AbstractState {
12     public void to0(StateManager sm) { print("to0");sm.setState(new State0()); } // 允许重置
13     public void toC(StateManager sm) { print("toC");sm.setState(new StateC()); } // 允许转移到C
14 }
15 
16 public class StateC extends AbstractState {
17     public void to0(StateManager sm) { print("to0");sm.setState(new State0()); } // 允许重置
18     public void toC(StateManager sm) { print("toC_Again"); } // 覆盖,走另一个逻辑
19 }

简单举例吧,状态转移就点到为止。至此一个由基本的状态模式改造的模型就写完了,一个抽象父类提供一个默认抛出不支持异常的方法,子类需要实现转移到哪个状态,就重写哪个方法。问题很明显,代码冗余很严重。发现toC方法写错了,我要改3个地方。Java容器类库里AbstractList里提供默认抛出不支持操作异常的目的是避免接口爆炸,不能随随便便就抄过来的。但是,这个逻辑还是有应用在这个场景下的味道在里面的,只不过用反了。不应该是给无能者赋予能力,而是给健全者予以阉割!第二版更改如下:

抽象父类:

1 public abstract class AbstractState implement State {
2     public void to0(StateManager sm) { print("to0");sm.setState(new State0()); } // 允许重置
3     public void toA(StateManager sm) { print("toA");sm.setState(new StateA()); } // 允许转移到A
4     public void toB(StateManager sm) { print("toB");sm.setState(new StateB()); } // 允许转移到B
5     public void toC(StateManager sm) { print("toC");sm.setState(new StateC()); } // 允许转移到C
6 }

具体子类:

 1 public class State0 extends AbstractState {
 2     public void to0(StateManager sm) { throw new UnsupportedOperationException();} // 禁止的状态转移阉割掉
 3     public void toB(StateManager sm) { throw new UnsupportedOperationException();} // 禁止的状态转移阉割掉
 4     public void toC(StateManager sm) { throw new UnsupportedOperationException();} // 禁止的状态转移阉割掉
 5 }
 6  
 7 public class StateA extends AbstractState {
 8     public void toA(StateManager sm) { throw new UnsupportedOperationException();} // 禁止的状态转移阉割掉
 9 }
10 
11 public class StateB extends AbstractState {
12     public void toA(StateManager sm) { throw new UnsupportedOperationException();} // 禁止的状态转移阉割掉
13     public void toB(StateManager sm) { throw new UnsupportedOperationException();} // 禁止的状态转移阉割掉
14 }
15 
16 public class StateC extends AbstractState {
17     public void toA(StateManager sm) { throw new UnsupportedOperationException();} // 禁止的状态转移阉割掉
18     public void toB(StateManager sm) { throw new UnsupportedOperationException();} // 禁止的状态转移阉割掉
19     public void toC(StateManager sm) { print("toC_Again"); } // 覆盖,走另一个逻辑
20 }

第二版修复了第一版出现的问题,所有实现功能的代码只出现了一次,,但还是不够好,抽象类的作用已经发生了变化,和接口有重叠。鉴于状态不会再有变动,接口可以去掉了,留抽象类足矣。

感觉还是不够好,写得很垃圾,以后再改吧,现在这样足够能用了,也没有多线程场景,不过以后要是有的话问题可就大了。

欢迎提出意见指正

原文地址:https://www.cnblogs.com/cachedking/p/8061734.html