首页 > 其他分享 >【设计模式-行为型】状态模式

【设计模式-行为型】状态模式

时间:2025-01-22 13:57:50浏览次数:3  
标签:状态 GEAR car 模式 Car CarState message 设计模式 public

一、什么是状态模式

        什么是状态模式呢,这里我举一个例子来说明,在自动挡汽车中,挡位的切换是根据驾驶条件(如车速、油门踏板位置、刹车状态等)自动完成的。这种自动切换挡位的过程可以很好地用状态模式来描述。状态模式(State Pattern) 是一种行为型设计模式,它允许一个对象在其内部状态发生变化时(加速或者减速)改变其行为(换挡)。状态模式的核心思想是将对象的行为封装在不同的状态类中,使得对象的行为随着状态的改变而改变。这种模式特别适用于对象的行为依赖于其内部状态的场景。

二、为什么使用状态模式

  1. 清晰的职责划分:代码结构清晰,每个状态类的职责单一,易于理解和维护。例如,在自动挡汽车中,每个挡位的行为都封装在独立的状态类中,职责划分明确。

  2. 动态改变行为:减少了复杂的条件分支(如 if-elseswitch-case),使代码更加简洁和可读。例如,在自动挡汽车中,换挡逻辑由状态机自动处理,无需在主逻辑中写复杂的条件判断。

  3. 扩展性:符合开闭原则(对扩展开放,对修改封闭)。例如,在自动挡汽车中,新增一个挡位(如6挡)时,只需添加一个新的状态类,无需修改现有的换挡逻辑。

  4. 低耦合:状态类和上下文类之间的依赖关系减少,提高了代码的灵活性和可维护性。例如,在自动挡汽车中,Car 类与各个挡位状态类通过 GearState 接口交互,降低了耦合度。

  5. 适应复杂状态逻辑:能够清晰地表达状态转换逻辑,避免代码混乱。例如,在自动挡汽车中,换挡逻辑可能涉及多种条件(如车速、油门位置等),状态机模式能够清晰地表达这些逻辑。

三、状态模式的示例

3.1 状态模式示例及角色

1. State:定义状态接口(行为)

定义了所有挡位状态的通用接口,包含所有挡位共有的方法,例如加速、减速等

public interface GearState {
    void accelerate(Car car); // 加速时的行为
    void decelerate(Car car); // 减速时的行为
}

2. ConcreteState:实现具体状态类(档位)

每个挡位(如1挡、2挡、3挡、4挡、5挡等)都实现状态接口,并定义在该挡位下的行为。

public class FirstGear implements GearState {
    @Override
    public void accelerate(Car car) {
        System.out.println("当前1档:加速...");
        car.setState(new SecondGear()); // 切换到2挡
    }

    @Override
    public void decelerate(Car car) {
        System.out.println("当前1档:减速...");
        car.setState(new NeutralGear()); // 切换到空挡
    }
}

public class SecondGear implements GearState {
    @Override
    public void accelerate(Car car) {
        System.out.println("当前2档:加速...");
        car.setState(new ThirdGear()); // 切换到3挡
    }

    @Override
    public void decelerate(Car car) {
        System.out.println("当前2档:减速...");
        car.setState(new FirstGear()); // 切换到1挡
    }
}

public class ThirdGear implements GearState {
    @Override
    public void accelerate(Car car) {
        System.out.println("当前3档:加速...");
        car.setState(new FourthGear()); // 切换到4挡
    }

    @Override
    public void decelerate(Car car) {
        System.out.println("当前3档:减速...");
        car.setState(new SecondGear()); // 切换到2挡
    }
}

public class FourthGear implements GearState {
    @Override
    public void accelerate(Car car) {
        System.out.println("当前4档:加速...");
        car.setState(new FifthGear()); // 切换到5挡
    }

    @Override
    public void decelerate(Car car) {
        System.out.println("当前1档:减速...");
        car.setState(new ThirdGear()); // 切换到3挡
    }
}

public class FifthGear implements GearState {
    @Override
    public void accelerate(Car car) {
        System.out.println("当前5档:加速...");
        // 保持在5挡
    }

    @Override
    public void decelerate(Car car) {
        System.out.println("当前5档:减速...");
        car.setState(new FourthGear()); // 切换到4挡
    }
}

public class NeutralGear implements GearState {
    @Override
    public void accelerate(Car car) {
        System.out.println("当前空档:加速...");
        car.setState(new FirstGear()); // 切换到1挡
    }

    @Override
    public void decelerate(Car car) {
        System.out.println("当前空档:减速...");
        // 保持在空挡
    }
}

3、Context(上下文):(当前车辆,记录当前状态)

上下文可以被视为汽车的驾驶系统,它包含当前挡位的状态,并根据驾驶员的操作切换挡位

public class Car {
    private GearState currentState;

    public Car() {
        this.currentState = new NeutralGear(); // 初始状态为空挡
    }

    public void setState(GearState state) {
        this.currentState = state;
    }

    public void accelerate() {
        currentState.accelerate(this);
    }

    public void decelerate() {
        currentState.decelerate(this);
    }
}

4、场景(开车)

public class Main {
    public static void main(String[] args) {
        Car car = new Car();

        car.accelerate(); // 初始状态为空挡,加速后切换到1挡
        car.accelerate(); // 当前状态为1挡,加速后切换到2挡
        car.accelerate(); // 当前状态为2挡,加速后切换到3挡
        car.decelerate(); // 当前状态为3挡,减速后切换到2挡
        car.decelerate(); // 当前状态为2挡,减速后切换到1挡
        car.decelerate(); // 当前状态为1挡,减速后切换到空挡
    }
}


//输出
当前0档:加速...
当前1档:加速...
当前2档:加速...
当前3档:加速...
当前3档:减速...
当前2档:减速...
当前1档:减速...
当前0档:减速...

3.2 在JAVA开发中常用的Spring状态机

        在Spring框架中,可以使用Spring State Machine来实现状态机模式。Spring State Machine是一个功能强大的状态机框架,支持定义状态、事件和状态转换,并且可以与Spring生态系统无缝集成。在实际开发中,可能使用Spring框架比较多,一般都是直接使用现成的Spring State Machine 来实现状态模式。

1、集成依赖包

<dependency>
	<groupId>org.springframework.statemachine</groupId>
	<artifactId>spring-statemachine-core</artifactId>
	<version>2.1.3.RELEASE</version>
</dependency>

2、定义状态和事件

//车辆档位枚举类
public enum CarState {
    NEUTRAL,     //空挡
    FIRST_GEAR,  //一档
    SECOND_GEAR, //二挡
    THIRD_GEAR,  //三挡
    FOURTH_GEAR, //四挡
    FIFTH_GEAR;   //五档
}


//车辆行为枚举类
public enum CarEvent {
    ACCELERATE,     //加速行为
    DECELERATE;     //减速行为
}

3、配置状态机

@Configuration
@EnableStateMachine(name="carStateMachine")
public class CarStateMachineConfig extends StateMachineConfigurerAdapter<CarState, CarEvent> {
    public void configure(StateMachineStateConfigurer<CarState, CarEvent> states) throws Exception {
        states.withStates().initial(CarState.NEUTRAL).states(EnumSet.allOf(CarState.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<CarState, CarEvent> states) throws Exception {
        states.withExternal().source(CarState.NEUTRAL).target(CarState.FIRST_GEAR).event(CarEvent.ACCELERATE)
                .and().withExternal().source(CarState.FIRST_GEAR).target(CarState.SECOND_GEAR).event(CarEvent.ACCELERATE)
                .and().withExternal().source(CarState.SECOND_GEAR).target(CarState.THIRD_GEAR).event(CarEvent.ACCELERATE)
                .and().withExternal().source(CarState.THIRD_GEAR).target(CarState.FOURTH_GEAR).event(CarEvent.ACCELERATE)
                .and().withExternal().source(CarState.FOURTH_GEAR).target(CarState.FIFTH_GEAR).event(CarEvent.ACCELERATE)
                .and().withExternal().source(CarState.FIFTH_GEAR).event(CarEvent.ACCELERATE) // No change
                .and().withExternal().source(CarState.FIFTH_GEAR).target(CarState.FOURTH_GEAR).event(CarEvent.DECELERATE)
                .and().withExternal().source(CarState.FOURTH_GEAR).target(CarState.THIRD_GEAR).event(CarEvent.DECELERATE)
                .and().withExternal().source(CarState.THIRD_GEAR).target(CarState.SECOND_GEAR).event(CarEvent.DECELERATE)
                .and().withExternal().source(CarState.SECOND_GEAR).target(CarState.FIRST_GEAR).event(CarEvent.DECELERATE)
                .and().withExternal().source(CarState.FIRST_GEAR).target(CarState.NEUTRAL).event(CarEvent.DECELERATE);
    }

    // 配置状态机持久化
    @Bean
    public DefaultStateMachinePersister machinePersister() {
        return new DefaultStateMachinePersister<>(new StateMachinePersist<Object, Object, Car>() {

            @Override
            public void write(StateMachineContext<Object, Object> stateMachineContext, Car car) throws Exception {
                //持久化操作。可以通过任何形式进行持久化。redis 、 mongodb、mysql,ecache
            }

            @Override
            public StateMachineContext<Object, Object> read(Car car) throws Exception {
                // 从持久化组件里进行读取
                return new DefaultStateMachineContext(car.getCarState(), null, null, null);
            }
        });
    }
}

4、定义状态监听器

        在Spring State Machine中,可以通过@WithStateMachine注解和@OnTransition注解来定义状态监听器。这些监听器会在状态转换时被触发。

// 监听器是监听到 action 后进行状态的一个变更。
@Slf4j
@Component("carStateListener")
@WithStateMachine(name="carStateMachine")
public class CarStateListener {
    @OnTransition(source = "NEUTRAL", target = "FIRST_GEAR")
    public boolean onAccelerateFromNeutral(Message<CarEvent> message) {
        log.info("Accelerating from NEUTRAL to FIRST_GEAR");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.FIRST_GEAR);
        return true;
    }

    @OnTransition(source = "FIRST_GEAR", target = "SECOND_GEAR")
    public boolean onAccelerateFromFirstGear(Message<CarEvent> message) {
        log.info("Accelerating from FIRST_GEAR to SECOND_GEAR");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.SECOND_GEAR);
        return true;
    }

    @OnTransition(source = "SECOND_GEAR", target = "THIRD_GEAR")
    public boolean onAccelerateFromSecondGear(Message<CarEvent> message) {
        log.info("Accelerating from SECOND_GEAR to THIRD_GEAR");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.THIRD_GEAR);
        return true;
    }

    @OnTransition(source = "THIRD_GEAR", target = "FOURTH_GEAR")
    public boolean onAccelerateFromThirdGear(Message<CarEvent> message) {
        log.info("Accelerating from THIRD_GEAR to FOURTH_GEAR");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.FOURTH_GEAR);
        return true;
    }

    @OnTransition(source = "FOURTH_GEAR", target = "FIFTH_GEAR")
    public boolean onAccelerateFromFourthGear(Message<CarEvent> message) {
        log.info("Accelerating from FOURTH_GEAR to FIFTH_GEAR");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.FIFTH_GEAR);
        return true;
    }

    @OnTransition(source = "FIFTH_GEAR", target = "FOURTH_GEAR")
    public boolean onDecelerateFromFifthGear(Message<CarEvent> message) {
        log.info("Decelerating from FIFTH_GEAR to FOURTH_GEAR");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.FOURTH_GEAR);
        return true;
    }

    @OnTransition(source = "FOURTH_GEAR", target = "THIRD_GEAR")
    public boolean onDecelerateFromFourthGear(Message<CarEvent> message) {
        log.info("Decelerating from FOURTH_GEAR to THIRD_GEAR");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.THIRD_GEAR);
        return true;
    }

    @OnTransition(source = "THIRD_GEAR", target = "SECOND_GEAR")
    public boolean onDecelerateFromThirdGear(Message<CarEvent> message) {
        log.info("Decelerating from THIRD_GEAR to SECOND_GEAR");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.SECOND_GEAR);
        return true;
    }

    @OnTransition(source = "SECOND_GEAR", target = "FIRST_GEAR")
    public boolean onDecelerateFromSecondGear(Message<CarEvent> message) {
        log.info("Decelerating from SECOND_GEAR to FIRST_GEAR");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.FIRST_GEAR);
        return true;
    }

    @OnTransition(source = "FIRST_GEAR", target = "NEUTRAL")
    public boolean onDecelerateFromFirstGear(Message<CarEvent> message) {
        log.info("Decelerating from FIRST_GEAR to NEUTRAL");
        Car car = (Car) message.getHeaders().get("car");
        car.setCarState(CarState.NEUTRAL);
        return true;
    }

}

4、使用状态机

@Service
public class CarService {

    @Resource
    private StateMachine<CarState, CarEvent> carStateMachine;

    @Resource
    private StateMachinePersister<CarState, CarEvent, Car> carMachinePersister;

    //模拟一个存储
    private Car car = new Car();


    //加速方法
    public Car acc() {
        if (car.getCarState() == null){
            car.setCarState(CarState.NEUTRAL);
        }
        // 书写逻辑
        Message message = MessageBuilder
                    .withPayload(CarEvent.ACCELERATE)
                .setHeader("car", car).build();
            if(changeStateAction(message,car)) {
                return car;
            }
        return car;
    }

    //减速方法
    public Car dece() {
        if (car.getCarState() == null){
            car.setCarState(CarState.NEUTRAL);
        }
        // 书写逻辑
        Message message = MessageBuilder
                .withPayload(CarEvent.DECELERATE)
                .setHeader("car", car).build();
        if(changeStateAction(message,car)) {
            return car;
        }
        return car;
    }

    private boolean changeStateAction(Message<CarEvent> message, Car car) {
        try {
            carStateMachine.start();
            //尝试恢复状态机状态
            carMachinePersister.restore(carStateMachine, car); // 待议
            boolean res = carStateMachine.sendEvent(message);
            //持久化状态机状态
            carMachinePersister.persist(carStateMachine, car); // 持久
            return res;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            carStateMachine.stop();
        }
        return false;
    }
}

4、场景(开车)

@SpringBootApplication
public class CarApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(DesignApplication.class, args);
		CarService carService = context.getBean(CarService.class);

		Car car;
		car = carService.acc(); // 初始状态为空挡,加速后切换到1挡
		System.out.println("After accelerate: " + car.getCarState());
		car = carService.acc(); // 当前状态为1挡,加速后切换到2挡
		System.out.println("After accelerate: " + car.getCarState());
		car = carService.dece(); // 当前状态为2挡,减速后切换到1挡
		System.out.println("After decelerate: " + car.getCarState());
		car = carService.dece(); // 当前状态为1挡,减速后切换到空挡
		System.out.println("After decelerate: " + car.getCarState());
    }
}


//输出
After accelerate: FIRST_GEAR
After accelerate: SECOND_GEAR
After decelerate: FIRST_GEAR
After decelerate: NEUTRAL

标签:状态,GEAR,car,模式,Car,CarState,message,设计模式,public
From: https://blog.csdn.net/qq_36038282/article/details/145284426

相关文章

  • 比简单工厂更好的 - 工厂方法模式(Factory Method Pattern)
    工厂方法模式(FactoryMethodPattern)工厂方法模式(FactoryMethodPattern)工厂方法模式(FactoryMethodPattern)概述工厂方法模式(FactoryMethodPattern)结构图工厂方法模式(FactoryMethodPattern)涉及的角色talkischeap,showyoumycode总结工厂方法模式(FactoryM......
  • 9、智能驾驶域控的工作模式与启动
    针对域控制器硬件工作模式与启动需支撑L2+功能实现的要求,以下是对相关要求的概述:一、域控制器硬件工作模式要求域控制器硬件需支持下电模式、待机模式、激活模式、最小风险策略模式等,以满足自动驾驶系统在不同场景下的需求。下电模式:当车辆处于完全关闭状态时,域控制器硬件应......
  • 【Azure APIM】APIM服务配置网络之后出现3443端口不通,Management Endpoint不健康状态
    问题描述APIM服务在配置网络之后,查看网络状态发现ManagementEndpoint是不健康状态,提示无法连接到3443端口。错误消息:Failedtoconnecttomanagementendpointatxxxxxxxx.management.azure-api.cn:3443foraservicedeployedinavirtualnetwork.Makesuretofollo......
  • 「全网最细 + 实战源码案例」设计模式——六大设计原则
    目的提高软件系统的可维护性和可复用性,增加软件的可拓展性和灵活性,程序员遵循6条原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本。开闭原则(OCP)核心思想1.对拓展开放软件模块应该在不修改原有代码的情况下,通过扩展的方式增加新功能。目标:提高系统的可......
  • 「全网最细 + 实战源码案例」设计模式——单例设计模式
    核心思想:属于创建型设计模式,核心目的是确保一个类在整个程序运行期间只有一个实例,并提供一个全局访问点来获取该实例。控制共享资源的访问(如数据库链接、配置管理、日志处理器等)真实世界类比:政府是单例模式的一个很好的示例。一个国家只有一个官方政府。不管组成政府的每个......
  • 策略模式和职责链模式实现坦克大战
    目录:一个实例讲完23种设计模式当前:策略模式职责链观察者上一篇《命令模式坦克大战简单实现(java实现)》需求:坦克大战创建两种坦克坦克类型射程速度b7070米时/70公里b5050米时/70公里简单说明一下:这任然用坦克大战的需求,实现了如下3种模式策略职责链观察者(这里的观察......
  • SQL进阶实战技巧:用户会话内行为模式挖掘
    目录0问题描述 1数据准备2问题分析3小结 往期精彩0问题描述分析用户在每个会话内的行为序列,找出最常见的前N种行为模式,并按用户分群。用户表结构和数据假设有名为user_behavior_log的用户行为日志表,包含以下字段:字段名数据类型描述user_idINT用户IDbehav......
  • uniapp——App 监听下载文件状态,打开文件(三)
    5+实现下载文件并打开这里演示,导出Excel表格文章目录5+实现下载文件并打开DEMO监听下载进度效果图为什么totalSize一直为0?相关Api:downloaderDEMO提示:请求方式支持:GET、POST;POST方式需要设置Content-Type;暂停下载任务:dtask.pause();取消下载任务:d......
  • iStore网关(旁路由)模式设置教程
    OpenWrt网关(旁路由)模式设置教程本文是在帮助小白用户快速设置OpenWrt设备(如N1)为网关(旁路由)模式。通过以下步骤,你可以在三分钟内完成设置,让设备顺利上网。Step1:登录OpenWrt系统后台通过浏览器访问OpenWrt的管理界面,通常为192.168.1.1(如未更改过)。输入用户名......
  • Golang学习笔记_28——工厂方法模式
    Golang学习笔记_25——协程Golang学习笔记_26——通道Golang学习笔记_27——单例模式文章目录工厂方法模式1.介绍2.优点3.类图4.实现源码工厂方法模式1.介绍工厂方法模式(FactoryMethod)是一种创建型设计模式,它提供了一种创建对象的接口,但由子类决定要实......