状态模式实战

状态模式

介绍

概念阐述: 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。

何时使用: 代码中包含大量与状态有关的条件语句。

如何解决: 将各种具体的状态类抽象出来。

关键代码: 抽象出各种状态类,如StartState,NextState,StopState三种状态,增加状态接口State,增加一个行为随着状态对象改变而改变的 Context 对象,Context对象和具体状态对象相互引用。

应用实例: 如司机开车,汽车启动状态对应司机动作,汽车平稳前行对应司机动作,停车对应司机动作,汽车不同状态对应司机不同的行为,这便是一种状态模式

使用场景: 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者。

注意事项:

  1. 在行为受状态约束的时候使用状态模式,而且状态不超过 5 个
  2. 如果此状态模式只在单一场景使用且独有方法不多,可考虑使用内部类减少对象数量
  3. 一定要灵活应用,不要硬套,按状态分类处理是基本思路,按实际情况可以随意发挥

优点:

  1. 结构清晰,易于维护
  2. 封装了状态转换规则
  3. 可以从任何状态点切入执行
  4. 允许状态转换逻辑与状态对象合成一体

缺点:

  1. 状态模式的使用必然会增加系统类和对象的个数。
  2. 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
  3. 状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态。

实战

第一步: 列举所有状态 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方法,查看执行结果

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值