状态模式
介绍
概念阐述: 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
何时使用: 代码中包含大量与状态有关的条件语句。
如何解决: 将各种具体的状态类抽象出来。
关键代码: 抽象出各种状态类,如StartState,NextState,StopState三种状态,增加状态接口State,增加一个行为随着状态对象改变而改变的 Context 对象,Context对象和具体状态对象相互引用。
应用实例: 如司机开车,汽车启动状态对应司机动作,汽车平稳前行对应司机动作,停车对应司机动作,汽车不同状态对应司机不同的行为,这便是一种状态模式
使用场景: 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者。
注意事项:
- 在行为受状态约束的时候使用状态模式,而且状态不超过 5 个
- 如果此状态模式只在单一场景使用且独有方法不多,可考虑使用内部类减少对象数量
- 一定要灵活应用,不要硬套,按状态分类处理是基本思路,按实际情况可以随意发挥
优点:
- 结构清晰,易于维护
- 封装了状态转换规则
- 可以从任何状态点切入执行
- 允许状态转换逻辑与状态对象合成一体
缺点:
- 状态模式的使用必然会增加系统类和对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
- 状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态。
实战
第一步: 列举所有状态 StartState,NextState,StopState 及其上下关系
第二步: 增加状态基类,提取公共方法
public interface State {
void action();
}
第三步: 增加具体状态类及Context类
// 开始状态
@Slf4j
public class StartState implements State{
public ContextService contextService;
public StartState(ContextService contextService){
this.contextService = contextService;
}
@Override
public void action() {
// 执行当前状态处理逻辑
handle();
// 变更状态
contextService.updateState("next");
// 执行下一状态,可以一直执行下去(如果各个状态有公共代码段可一起提到主类里)
if(contextService.state != null){
contextService.state.action();
}
}
/**
* 当前状态处理逻辑
*/
public void handle(){
log.debug("执行start状态逻辑");
}
}
// 下一状态
@Slf4j
public class NextState implements State{
public ContextService contextService;
public NextState(ContextService contextService){
this.contextService = contextService;
}
@Override
public void action() {
// 执行当前状态处理逻辑
handle();
// 变更状态
contextService.updateState("stop");
// 执行下一状态,可以一直执行下去(如果各个状态有公共代码段可一起提到主类里)
if(contextService.state != null){
contextService.state.action();
}
}
/**
* 当前状态处理逻辑
*/
public void handle(){
log.debug("执行next状态逻辑");
}
}
// 停止状态
@Slf4j
public class StopState implements State{
public ContextService contextService;
public StopState(ContextService contextService){
this.contextService = contextService;
}
@Override
public void action() {
// 执行当前状态处理逻辑
handle();
// 变更状态
contextService.updateState(ContextService.FINISH);
// 执行下一状态,可以一直执行下去(如果各个状态有公共代码段可一起提到主类里)
if(contextService.state != null){
contextService.state.action();
}
}
/**
* 当前状态处理逻辑
*/
public void handle(){
log.debug("执行stop状态逻辑");
}
}
@Slf4j
public class ContextService {
public State state;
public static final String FINISH = "FINISH";
/**
* 更新状态
* 状态切换放到主类中,可避免增加状态维护上下关系时对其他状态类方法的修改
* @param flag 状态获取依赖参数
*/
public void updateState(String flag){
log.debug("切换状态{}",flag);
state = getState(flag);
}
/**
* 根据标识获取不同状态(工厂模式)
* @param flag 状态获取依赖参数
* @return
*/
public State getState(String flag){
switch (flag){
case "start": return new StartState(this);
case "next": return new NextState(this);
case "stop": return new StopState(this);
default: return null;
}
}
}
第四步: 增加测试类
@Service
public class Test {
public static void main(String[] args){
ContextService contextService = new ContextService();
// 设置初始状态
contextService.updateState("start");
if(contextService.state != null){
contextService.state.action();
}
}
}
第五步: 执行main方法,查看执行结果