本文介绍状态模式。
概念
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
结构和工作原理
- Context:上下文类,是拥有状态的对象,持有抽象状态类State的实例,该实例定义当前的状态,在具体实现时,它是一个State子类的对象,可以定义初始状态
- State:抽象状态类,用于定义一个接口以封装与环境类的一个特定状态相关的行为
- ConcreteState:具体状态类,抽象状态类的子类,每一个子类定义一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同具体状态类其行为有所不同
状态模式描述了对象的状态变化以及对象在不同状态下的不同行为,适用于对象状态需要经常切换且在不同状态下对象的行为不同。
状态模式将对象本身决定状态的属性抽取出来,封装成抽象状态类,并将不同的状态用不同的具体抽象类表示,实现不同状态下的行为,包括状态之间的转换。
环境类持有抽象状态类的引用,可以在运行时将任一具体状态对象类设置到环境类中,从而状态类可以改变内部状态随之改变行为,环境类有时可以充当状态管理器的角色,可以在环境类中对状态进行切换操作。
优点:
- 封装了状态转换的规则
- 将状态抽取成类,使得增加状态变得方便
- 允许状态转换逻辑与状态对象合成一体,而不是繁琐冗长的条件语句块
- 可以让多个环境对象共享
缺点:
- 状态对象会导致系统类和对象的个数增加
- 状态模式的结构和实现较为复杂,容易使程序结构和代码混乱
- 新增状态类时要修改状态转换的代码,违反了开闭原则
因为涉及到环境类状态的设置,那么状态类必然需要与环境类进行通信,一种方式是状态类也持有环境类的引用,另一种方式是通过传递环境类引用给状态类的方法,从面向对象的角度来看,这两者都不是很优雅。
代码示例
public class Process {
private Long processId;
private String processTitle;
private State state;
public Process(Long processId, String processTitle) { this.processId = processId; this.processTitle = processTitle; }
public State getState() { return state; }
public void setState(State state) { state.setProcess(this); this.state = state; this.getState().handle(); } }
|
public abstract class State {
protected String stateName;
protected Boolean opinion;
protected Process process;
public abstract void handle();
public void setProcess(Process process) { this.process = process; } }
|
@Slf4j public class StartState extends State {
private static final String START_STATE = "startState";
public static StartState of() { return new StartState(); }
@Override public void handle() { this.stateName = START_STATE; this.opinion = true; log.info("StartState- handle- stateName: {}, opinion:{}", this.stateName, this.opinion); this.process.setState(LeaderApprovalState.of()); } }
|
@Slf4j public class LeaderApprovalState extends State {
private static final String LEADER_STATE = "leaderApproval";
public static LeaderApprovalState of() { return new LeaderApprovalState(); }
@Override public void handle() { this.stateName = LEADER_STATE; this.opinion = Math.random() < 0.8; log.info("LeaderApprovalState- handle- stateName:{}, opinion:{}", this.stateName, this.opinion); if (opinion) { this.process.setState(new HumanResourceApprovalState()); } else { this.process.setState(EndState.ofFalse()); } } }
|
@Slf4j public class HumanResourceApprovalState extends State {
private static final String HUMAN_RESOURCE_STATE = "humanResourceApproval";
public static HumanResourceApprovalState of() { return new HumanResourceApprovalState(); }
@Override public void handle() { this.stateName = HUMAN_RESOURCE_STATE; this.opinion = Math.random() < 0.8; log.info("HumanResourceApprovalState- handle- stateName:{}, opinion:{}", HUMAN_RESOURCE_STATE, opinion); this.process.setState(EndState.of(opinion)); } }
|
@Slf4j public class EndState extends State {
private static final String END_STATE = "endState";
public static EndState of(Boolean opinion) { EndState endState = new EndState(); endState.opinion = opinion; return endState; }
public static EndState ofFalse() { EndState endState = new EndState(); endState.opinion = false; return endState; }
@Override public void handle() { this.stateName = END_STATE; log.info("EndState- handle- stateName:{}, opinion:{}", this.stateName, this.opinion); } }
|
public class StateClient {
public static void main(String[] args) { Process process = new Process(1L, "vocation"); process.setState(StartState.of()); } }
|
参考资料
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/state.html
https://juejin.im/post/583e9eb4a22b9d006c23d431