状态模式
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
状态模式主要解决了当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态转移的判断逻辑转移到表达不同状态的一系列类当中,可以把复杂的逻辑简单化。
结构图:
State 接口,抽象的状态处理类,定义一个接口以封装与 Context 的一个特定状态相关的行为
public interface State {
void handle(Context context);
}
ConcreateState 具体状态处理类,每一个子类实现一个与一个Context 持有的状态相关的行为
public class ConcreateStateA implements State {
@OverrideA
public void handle(Context context) {
System.out.println("deal with concreateStateA");
context.setState(new ConcreateStateB());
}
}
public class ConcreateStateB implements State {
@Override
public void handle(Context context) {
System.out.println("deal with concreateStateB");
context.setState(new ConcreateStateA());
}
}
Context 类 ,维护一个 ConcreateState 子类的实例,这个实例定义了当前的状态
public class Context {
private State state;
public void process() {
state.handle(this);
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
}
客户端程序
public class Main {
public static void main(String[] args) {
Context context = new Context();
//设置初始状态为 ConcreateStateA
context.setState(new ConcreateStateA());
// 不断请求,切换状态
context.process();
context.process();
context.process();
/* output
deal with concreateStateA
deal with concreateStateB
deal with concreateStateA
*/
}
}
在SprigBoot 中优雅的使用
因为Spring 中已经有IOC 容器帮我们管理所有 bean 了,那么这里可以将所有ConcreateState(具体的状态处理)也交给 IOC 管理 ,而状态的流程则可以根据业务规则配置在枚举类中,
状态流转枚举类
public enum StateEnum {
START("ConcreateStateA", "start_process", "开始", "ConcreateStateB"),
DEAL("ConcreateStateB", "deal_process", "处理", "BACKUP"),
BACKUP("BACKUP", "start_process", "备份", "END");
//当前状态码
private String code;
//状态英文名称
private String enName;
//状态中文名称
private String cnName;
//下一个状态
private String nextStateCode;
StateEnum(String code, String enName, String cnName, String nextStateCode) {
this.code = code;
this.enName = enName;
this.nextStateCode = nextStateCode;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getEnName() {
return enName;
}
public void setEnName(String enName) {
this.enName = enName;
}
public String getCnName() {
return cnName;
}
public void setCnName(String cnName) {
this.cnName = cnName;
}
public String getNextStateCode() {
return nextStateCode;
}
public void setNextStateCode(String nextStateCode) {
this.nextStateCode = nextStateCode;
}
}
因此 State 接口处理方法不需要再传入 Context
public interface State {
void handle();
}
将具体状态处理类注册到 IOC 中,bean的名字为状态的名称,且具体状态处理类只做业务处理
@Service("ConcreateStateA")
public class ConcreateStateA implements State {
@Override
public void handle() {
System.out.println("I'm concreateStateA");
}
}
@Service("ConcreateStateA")
public class ConcreateStateB implements State {
@Override
public void handle() {
System.out.println("I'm concreateStateB");
}
}
Context 则需要负责根据调用者的状态名称从IOC 容器获取对应状态处理器类
@Service
public class Context {
@Autowired
ApplicationContext applicationContext;
public void process(String statusName) {
State state = applicationContext.getBean(statusName, State.class);
state.handle();
changeStatus(statusName);
}
// 统一修改数据状态
public void changeStatus(String statusName) {
String nextStateCode = StateEnum.valueOf(statusName).getNextStateCode();
//变更状态为 nextStateCode
}
这样当需要时,便可以将 context 注入到调用者的类中,执行 context.process 方法,通过传入对应枚举状态类中的 code 来获取状态处理类进行处理
总结:
状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来