状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题
系统中某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理
状态模式定义如下:
状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类
Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。
● State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
● ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
在状态模式中,我们将对象在不同状态下的行为封装到不同的状态类中,为了让系统具有更好的灵活性和可扩展性,同时对各状态下的共有行为进行封装,我们需要对状态进行抽象,引入了抽象状态类角色,其典型代码如下所示:
context:
package com.example.demo.designpattern.state;
/**
* Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。
* ————————————————
* 境类实际上是真正拥有状态的对象,我们只是将环境类中与状态有关的代码提取出来封装到专门的状态类中。在状态模式结构图中,环境类Context与抽象状态类State之间存在单向关联关系,在Context中定义了一个State对象
*/
public class Context {
private State state; //维持一个对抽象状态对象的引用
private int value; //其他属性值,该属性值的变化可能会导致对象状态发生变化
public State getState() {
return state;
}
//设置状态对象
public void setState(State state) {
this.state = state;
}
public void request() {
// state.handle(); //调用状态对象业务方法
}
}
State
package com.example.demo.designpattern.state;
/**
* State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
*/
public abstract class State {
//
//声明抽象业务方法,不同的具体状态类可以不同的实现
public abstract void handle(Context context);
}
ConcreteState
package com.example.demo.designpattern.state;
/**
* ● ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
*/
public class StateA extends State {
@Override
public void handle(Context context) {
System.out.println("现在是状态A");
context.setState(this);
}
}
package com.example.demo.designpattern.state;
public class StateB extends State{
@Override
public void handle(Context context) {
System.out.println("现在是状态B");
context.setState(this);
}
}
package com.example.demo.designpattern.state;
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context();
StateA stateA = new StateA();
stateA.handle(context);
StateB stateB = new StateB();
stateB.handle(context);
}
}
spring的状态机
主要分为4个类
事件类:
package com.example.demo.designpattern.state.springstatemachine;
/**
* 事件枚举 开,关
**/
public enum Events {
ON,
OFF;
}
状态类:
package com.example.demo.designpattern.state.springstatemachine;
/**
* 状态枚举 灯开 ,灯关
*/
public enum States {
LIGHT_ON,
LIGHT_OFF;
}
业务类:
package com.example.demo.designpattern.state.springstatemachine;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.WithStateMachine;
@WithStateMachine
@Data
@Slf4j
public class BizBean {
/**
* @see States 设置初始化状态
*/
private String status = States.LIGHT_OFF.name();
//发生事件LIGHT_OFF,要执行的方法
@OnTransition(target = "LIGHT_OFF")
public void off() {
log.info("灯关了", States.LIGHT_OFF.name());
setStatus(States.LIGHT_OFF.name());
}
//发生事件LIGHT_ON,要执行的方法
@OnTransition(target = "LIGHT_ON")
public void on() {
log.info("灯开了", States.LIGHT_ON.name());
setStatus(States.LIGHT_ON.name());
}
}
状态机配置类:
package com.example.demo.designpattern.state.springstatemachine;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnableWithStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import java.util.EnumSet;
///**
// * 创建状态机配置类:
// */
@Configuration
注解表示用来启用spring状态机
@EnableStateMachine
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States,Events> {
@Override
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
states.withStates().initial(States.LIGHT_OFF) //设置状态机的初始状态,必须有
.states(EnumSet.allOf(States.class)); //状态机所有状态集合
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
transitions.withExternal()
// 当发生时间Events.ON ,则执行BizBean里面的方法 当前方法状态为States.LIGHT_OFF ,目标方法为 States.LIGHT_ON,即方法 @OnTransition(target = "LIGHT_ON")
.source(States.LIGHT_OFF).target(States.LIGHT_ON)
.event(Events.ON)
.and()
// 当发生时间Events.OFF ,则执行BizBean里面的方法 当前方法状态为States.LIGHT_ON ,目标方法为 States.LIGHT_OFF,即方法 @OnTransition(target = "LIGHT_OFF")
.withExternal()
.source(States.LIGHT_ON).target(States.LIGHT_OFF)
.event(Events.OFF);
}
}
测试:
package com.example.demo.designpattern.state.springstatemachine;
import org.springframework.statemachine.StateMachine;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
//spring状态机测试,状态机的状态在整个jvm中都存在
@RequestMapping(value ="statemachine")
@RestController
public class TestSpringStatementMachine {
@Resource
StateMachine<States,Events> stateMachine;
@RequestMapping(value = "testOn")
public void testMachine() {
stateMachine.start();//调用spring 状态机的初始化设置
stateMachine.sendEvent(Events.ON); // 事件开
// stateMachine.sendEvent(Events.PUBLISH);
// stateMachine.sendEvent(Events.ROLLBACK);
}
@RequestMapping(value = "testOff")
public void testMachineOff() {
stateMachine.start();//调用spring 状态机的初始化设置
stateMachine.sendEvent(Events.OFF); // 事件开
// stateMachine.sendEvent(Events.PUBLISH);
// stateMachine.sendEvent(Events.ROLLBACK);
}
}