1.定义
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
允许状态对象在其内部状态发生改变时改变其行为。使得这个对象看起来已经被修改了。
不同的状态的对象会产生不同的行为。用来解耦状态间的依赖。
2.场景
1.游戏中角色的状态改变,不同状态下的攻击模式或者行为不同。
2.工作流中,状态的审批流程。
3.案例1
1.模拟游戏中角色状态
在英雄联盟中的有的游戏有两种形态,或者是认为两种模式。当前切换不同模式时,技能会发生变化。
在这里就定义出一个技能接口,然后分普通状态和狂暴状态。
2.接口定义
//技能接口已经在之前策略模式中定义过,这里直接拿来用
public interface SkillState extends Skill{
}
3.定义实现类
@AllArgsConstructor
@NoArgsConstructor
public class NormalState implements SkillState{
private Hero hero;
/**
* 用于注册唯一标识
*
* @return
*/
@Override
public String getNo() {
return "NormalState";
}
@Override
public String Q() {
return "电能震荡";
}
@Override
public String W() {
return "超能电荷";
}
@Override
public String E() {
return "速之门";
}
@Override
public String R() {
hero.changeStatus(new CrazyState(hero));
return "墨丘利之炮切换至墨丘利之锤";
}
}
@AllArgsConstructor
@NoArgsConstructor
public class CrazyState implements SkillState{
private Hero hero;
/**
* 用于注册唯一标识
*
* @return
*/
@Override
public String getNo() {
return "CrazyState";
}
@Override
public String Q() {
return "苍穹之跃";
}
@Override
public String W() {
return "闪电领域";
}
@Override
public String E() {
return "雷霆一击加";
}
@Override
public String R() {
//切换状态
hero.changeStatus(new NormalState(hero));
return "墨丘利之锤切换至墨丘利之炮";
}
}
3.定义上下文管理器
public class Hero implements Skill {
/**
* 英雄名称
*/
private String name;
/**
* 英雄技能状态
*/
private SkillState skillState;
public Hero(){
//默认普通形态
this.skillState = new NormalState(this);
//默认英雄
this.name = "Jayce";
}
public SkillState getStatus(){
return this.skillState;
}
public void changeStatus(SkillState skillState){
this.skillState = skillState;
}
/**
* 用于注册唯一标识
*
* @return
*/
@Override
public String getNo() {
return this.name+skillState.getNo();
}
@Override
public String Q() {
return skillState.Q();
}
@Override
public String W() {
return skillState.W();
}
@Override
public String E() {
return skillState.E();
}
@Override
public String R() {
return skillState.R();
}
}
4.测试
public class TestApi {
public static void main(String[] args) {
Hero Jayce = new Hero();
//模拟杰斯连招 炮形态:QEW + 锤形态:Q+W+E
System.out.println(Jayce.Q());
System.out.println(Jayce.E());
System.out.println(Jayce.W());
System.out.println(Jayce.R());
System.out.println(Jayce.Q());
System.out.println(Jayce.W());
System.out.println(Jayce.E());
}
}
电能震荡
速之门
超能电荷
墨丘利之炮切换至墨丘利之锤
苍穹之跃
闪电领域
雷霆一击加
4.案例2:
1.模拟审核流程场景
审核流程:1创建编辑、2待审核、3审核中、4审核拒绝(可以撤审到编辑状态)、5审核关闭
定义状态抽象类
public abstract class State {
/**
* 提交审核
*
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result submit(String flowId, Enum<Status> currentStatus);
/**
* 审核通过
*
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result checkPass(String flowId, Enum<Status> currentStatus);
/**
* 审核拒绝
*
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result checkRefuse(String flowId, Enum<Status> currentStatus);
/**
* 撤审撤销
*
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result checkRevoke(String flowId, Enum<Status> currentStatus);
/**
* 审核完成
*
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result finish(String flowId, Enum<Status> currentStatus);
}
public enum Status {
// 1创建编辑、2待审核、3审核中、4审核拒绝(可以撤审到编辑状态)、5审核关闭
Editing, Check, Pass, Refuse, Finish
}
2.定义实现类
根据不同的状态去判断所能做的操作,后面几种状态类似,这里就直接省略了。
public class CheckState extends State{
/**
* 提交审核
*
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
@Override
public Result submit(String flowId, Enum<Status> currentStatus) {
return new Result("0001","不可重复提交任务!");
}
/**
* 审核通过
*
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
@Override
public Result checkPass(String flowId, Enum<Status> currentStatus) {
TaskService.execStatus(flowId, currentStatus, Status.Pass);
return new Result("0000","审核通过");
}
/**
* 审核拒绝
*
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
@Override
public Result checkRefuse(String flowId, Enum<Status> currentStatus) {
TaskService.execStatus(flowId, currentStatus, Status.Pass);
return new Result("0000","审核不通过");
}
/**
* 撤审撤销
* 退回到编辑状态
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
@Override
public Result checkRevoke(String flowId, Enum<Status> currentStatus) {
TaskService.execStatus(flowId, currentStatus, Status.Editing);
return new Result("0000","审核撤回到编辑状态");
}
/**
* 审核完成
*
* @param flowId 流程ID
* @param currentStatus 当前状态
* @return 执行结果
*/
@Override
public Result finish(String flowId, Enum<Status> currentStatus) {
return new Result("0001", "审核中不可完成审核");
}
}
3.状态处理器
public class StateHandler {
private Map<Enum<Status>, State> stateMap = new ConcurrentHashMap<Enum<Status>, State>();
public StateHandler() {
stateMap.put(Status.Check, new CheckState()); // 待审核
stateMap.put(Status.Finish, new FinishState()); // 已关闭
stateMap.put(Status.Editing, new EditingState()); // 编辑中
stateMap.put(Status.Pass, new PassState()); // 审核通过
stateMap.put(Status.Refuse, new RefuseState()); // 审核拒绝
}
public Result submit(String activityId, Enum<Status> currentStatus) {
return stateMap.get(currentStatus).submit(activityId, currentStatus);
}
public Result checkPass(String activityId, Enum<Status> currentStatus) {
return stateMap.get(currentStatus).checkPass(activityId, currentStatus);
}
public Result checkRefuse(String activityId, Enum<Status> currentStatus) {
return stateMap.get(currentStatus).checkRefuse(activityId, currentStatus);
}
public Result checkRevoke(String activityId, Enum<Status> currentStatus) {
return stateMap.get(currentStatus).checkRevoke(activityId, currentStatus);
}
public Result finish(String activityId, Enum<Status> currentStatus) {
return stateMap.get(currentStatus).finish(activityId, currentStatus);
}
}
4.模拟流程
public class TaskService {
/**
* 模拟数据库状态
*/
private static Map<String, Enum<Status>> statusMap = new ConcurrentHashMap<String, Enum<Status>>();
/**
* 初始化任务流程
* @param flowId
* @param status
*/
public static void init(String flowId, Enum<Status> status) {
TaskInfo task = new TaskInfo();
task.setFlowId(flowId);
task.setTaskName("请假审批流程");
task.setStatus(status);
task.setCreateDate(new Date());
statusMap.put(flowId, status);
}
/**
* 查询当前状态
*
* @param flowId 活动ID
* @return 查询结果
*/
public static Enum<Status> queryActivityStatus(String flowId) {
return statusMap.get(flowId);
}
/**
* 执行状态变更
*
* @param flowId 流程ID
* @param beforeStatus 变更前状态
* @param afterStatus 变更后状态 b
*/
public static synchronized void execStatus(String flowId, Enum<Status> beforeStatus, Enum<Status> afterStatus) {
if (!beforeStatus.equals(statusMap.get(flowId))) return;
statusMap.put(flowId, afterStatus);
}
}
5.测试
public class TestApi {
public static void main(String[] args) {
String flowId = "100001";
TaskService.init(flowId, Status.Editing);
StateHandler stateHandler = new StateHandler();
Result result = stateHandler.submit(flowId, Status.Editing);
System.out.println(JSONUtil.toJsonStr(result));
System.out.println(TaskService.queryActivityStatus(flowId));
}
}
{"code":"0000","status":"任务提交成功!"}
Check
5.总结
状态模式和策略有点类似,不同的就是策略中每个策略都是完全独立的。而状态模式没有限制状态之间的依赖,可以互相转变,也可以独立。
代码地址:GitHub - qianzzbatt/java-design-patterns at 514472e0e925b8da956240e16144419415823871
参考文章:
重学 Java 设计模式:实战状态模式「模拟系统营销活动,状态流程审核发布上线场景」 | bugstack 虫洞栈
https://blog.csdn.net/d303577562/article/details/118578336