一、什么是状态模式
什么是状态模式呢,这里我举一个例子来说明,在自动挡汽车中,挡位的切换是根据驾驶条件(如车速、油门踏板位置、刹车状态等)自动完成的。这种自动切换挡位的过程可以很好地用状态模式来描述。状态模式(State Pattern) 是一种行为型设计模式,它允许一个对象在其内部状态发生变化时(加速或者减速)改变其行为(换挡)。状态模式的核心思想是将对象的行为封装在不同的状态类中,使得对象的行为随着状态的改变而改变。这种模式特别适用于对象的行为依赖于其内部状态的场景。
二、为什么使用状态模式
-
清晰的职责划分:代码结构清晰,每个状态类的职责单一,易于理解和维护。例如,在自动挡汽车中,每个挡位的行为都封装在独立的状态类中,职责划分明确。
-
动态改变行为 :减少了复杂的条件分支(如
if-else
或switch-case
),使代码更加简洁和可读。例如,在自动挡汽车中,换挡逻辑由状态机自动处理,无需在主逻辑中写复杂的条件判断。 -
扩展性:符合开闭原则(对扩展开放,对修改封闭)。例如,在自动挡汽车中,新增一个挡位(如6挡)时,只需添加一个新的状态类,无需修改现有的换挡逻辑。
-
低耦合 :状态类和上下文类之间的依赖关系减少,提高了代码的灵活性和可维护性。例如,在自动挡汽车中,
Car
类与各个挡位状态类通过GearState
接口交互,降低了耦合度。 -
适应复杂状态逻辑:能够清晰地表达状态转换逻辑,避免代码混乱。例如,在自动挡汽车中,换挡逻辑可能涉及多种条件(如车速、油门位置等),状态机模式能够清晰地表达这些逻辑。
三、状态模式的示例
3.1 状态模式示例及角色
1. **State:**定义状态接口(行为)
定义了所有挡位状态的通用接口,包含所有挡位共有的方法,例如加速、减速等
java
public interface GearState {
void accelerate(Car car); // 加速时的行为
void decelerate(Car car); // 减速时的行为
}
2. ConcreteState:实现具体状态类(档位)
每个挡位(如1挡、2挡、3挡、4挡、5挡等)都实现状态接口,并定义在该挡位下的行为。
java
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(上下文):(当前车辆,记录当前状态)
上下文可以被视为汽车的驾驶系统,它包含当前挡位的状态,并根据驾驶员的操作切换挡位
java
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、场景(开车)
java
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、集成依赖包
java
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
2、定义状态和事件
java
//车辆档位枚举类
public enum CarState {
NEUTRAL, //空挡
FIRST_GEAR, //一档
SECOND_GEAR, //二挡
THIRD_GEAR, //三挡
FOURTH_GEAR, //四挡
FIFTH_GEAR; //五档
}
//车辆行为枚举类
public enum CarEvent {
ACCELERATE, //加速行为
DECELERATE; //减速行为
}
3、配置状态机
java
@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
注解来定义状态监听器。这些监听器会在状态转换时被触发。
java
// 监听器是监听到 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、使用状态机
java
@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、场景(开车)
java
@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