文章目录
状态模式(State Pattern)
状态模式的定义
- 状态模式(State Pattern)
- 状态模式的定义
- 状态模式的优点
- 状态模式的缺点
- 状态模式的结构
- 状态模式的实现
- 通用场景
- 流程审批场景
- 状态模式的适用场景
- 注意事项
当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。
状态模式的核心是封装,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。
状态模式的优点- 结构清晰,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足"单一职责原则"。
- 将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
- 状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
- 良好的封装性,这也是状态模式的基本要求,状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。
- 状态模式的使用必然会增加系统的类与对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
- 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码。
包含以下主要角色。
- 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
- 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
- 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
public abstract class State {
/**
* 定义一个环境角色,提供子类访问
*/
protected Context context;
/**
* 设置环境角色
*/
public void setContext(Context context) {
this.context = context;
}
/**
* 行为1
*/
public abstract void handle1();
/**
* 行为2
*/
public abstract void handle2();
}
public class Context {
/**
* 定义状态
*/
public final static State STATE1 = new ConcreteState1();
public final static State STATE2 = new ConcreteState2();
/**
* 当前状态
*/
private State currentState;
/**
* 获得当前状态
*/
public State getCurrentState() {
return currentState;
}
/**
* 设置当前状态
*/
public void setCurrentState(State currentState) {
this.currentState = currentState;
//切换状态
this.currentState.setContext(this);
}
/**
* 行为委托
*/
public void handle1() {
this.currentState.handle1();
}
public void handle2() {
this.currentState.handle2();
}
}
public class ConcreteState1 extends State {
@Override
public void handle1() {
System.out.println("State1 is doing things");
}
@Override
public void handle2() {
// 设置当前状态为stat2
super.context.setCurrentState(Context.STATE2);
// 过渡到state2状态,由Context实现
super.context.handle2();
}
}
public class ConcreteState2 extends State {
@Override
public void handle1() {
//设置当前状态为state1
super.context.setCurrentState(Context.STATE1);
//过渡到state1状态,由Context实现
super.context.handle1();
}
@Override
public void handle2() {
System.out.println("State2 is doing things");
}
}
public static void main(String[] args) {
//定义环境角色
Context context = new Context();
//初始化状态
context.setCurrentState(new ConcreteState1());
//行为执行
context.handle1();
context.handle2();
}
流程审批场景
public class ActivityInfo {
/**
* 活动ID
*/
private String activityId;
/**
* 活动名称
*/
private String activityName;
/**
* 活动状态
*/
private Enum status;
/**
* 开始时间
*/
private Date beginTime;
/**
* 结束时间
*/
private Date endTime;
public String getActivityId() {
return activityId;
}
public void setActivityId(String activityId) {
this.activityId = activityId;
}
public String getActivityName() {
return activityName;
}
public void setActivityName(String activityName) {
this.activityName = activityName;
}
public Enum getStatus() {
return status;
}
public void setStatus(Enum status) {
this.status = status;
}
public Date getBeginTime() {
return beginTime;
}
public void setBeginTime(Date beginTime) {
this.beginTime = beginTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
}
public class ActivityService {
private static final Map STATUS_MAP = new ConcurrentHashMap();
public static void init(String activityId, Enum status) {
// 模拟查询活动信息
ActivityInfo activityInfo = new ActivityInfo();
activityInfo.setActivityId(activityId);
activityInfo.setActivityName("早起学习打卡领奖活动");
activityInfo.setStatus(status);
activityInfo.setBeginTime(new Date());
activityInfo.setEndTime(new Date());
STATUS_MAP.put(activityId, status);
}
/**
* 查询活动信息
*
* @param activityId 活动ID
* @return 查询结果
*/
public static ActivityInfo queryActivityInfo(String activityId) {
// 模拟查询活动信息
ActivityInfo activityInfo = new ActivityInfo();
activityInfo.setActivityId(activityId);
activityInfo.setActivityName("早起学习打卡领奖活动");
activityInfo.setStatus(STATUS_MAP.get(activityId));
activityInfo.setBeginTime(new Date());
activityInfo.setEndTime(new Date());
return activityInfo;
}
/**
* 查询活动状态
*
* @param activityId 活动ID
* @return 查询结果
*/
public static Enum queryActivityStatus(String activityId) {
return STATUS_MAP.get(activityId);
}
/**
* 执行状态变更
*
* @param activityId 活动ID
* @param beforeStatus 变更前状态
* @param afterStatus 变更后状态 b
*/
public static synchronized void execStatus(String activityId, Enum beforeStatus, Enum afterStatus) {
if (!beforeStatus.equals(STATUS_MAP.get(activityId))) {
return;
}
STATUS_MAP.put(activityId, afterStatus);
}
}
public enum Status {
// 1创建编辑、2待审核、3审核通过(任务扫描成活动中)、4审核拒绝(可以撤审到编辑状态)、5活动中、6活动关闭、7活动开启(任务扫描成活动中)
Editing, Check, Pass, Refuse, Doing, Close, Open
}
public class Result {
public final static String CODE_ERROR = "0001";
public final static String CODE_OK = "0000";
/**
* 编码
*/
private String code;
/**
* 描述
*/
private String info;
public Result(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
/**
* 抽象状态类
*/
public abstract class State {
/**
* 活动提审
*
* @param activityId 活动ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result arraignment(String activityId, Enum currentStatus);
/**
* 审核通过
*
* @param activityId 活动ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result checkPass(String activityId, Enum currentStatus);
/**
* 审核拒绝
*
* @param activityId 活动ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result checkRefuse(String activityId, Enum currentStatus);
/**
* 撤审撤销
*
* @param activityId 活动ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result checkRevoke(String activityId, Enum currentStatus);
/**
* 活动关闭
*
* @param activityId 活动ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result close(String activityId, Enum currentStatus);
/**
* 活动开启
*
* @param activityId 活动ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result open(String activityId, Enum currentStatus);
/**
* 活动执行
*
* @param activityId 活动ID
* @param currentStatus 当前状态
* @return 执行结果
*/
public abstract Result doing(String activityId, Enum currentStatus);
}
/**
* 活动状态;待审核
*/
public class CheckState extends State {
@Override
public Result arraignment(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "待审核状态不可重复提审");
}
@Override
public Result checkPass(String activityId, Enum currentStatus) {
return new Result(Result.CODE_OK, "活动审核通过完成");
}
@Override
public Result checkRefuse(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Refuse);
return new Result(Result.CODE_OK, "活动审核拒绝完成");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Editing);
return new Result(Result.CODE_OK, "活动审核撤销回到编辑中");
}
@Override
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result(Result.CODE_OK, "活动审核关闭完成");
}
@Override
public Result open(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "非关闭活动不可开启");
}
@Override
public Result doing(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "待审核活动不可执行活动中变更");
}
}
/**
* 活动状态;活动关闭
*/
public class CloseState extends State {
@Override
public Result arraignment(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动关闭不可提审");
}
@Override
public Result checkPass(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动关闭不可审核通过");
}
@Override
public Result checkRefuse(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动关闭不可审核拒绝");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动关闭不可撤销审核");
}
@Override
public Result close(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动关闭不可重复关闭");
}
@Override
public Result open(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Open);
return new Result(Result.CODE_OK, "活动开启完成");
}
@Override
public Result doing(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动关闭不可变更活动中");
}
}
/**
* 活动状态;活动中
*/
public class DoingState extends State {
@Override
public Result arraignment(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动中不可提审");
}
@Override
public Result checkPass(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动中不可审核通过");
}
@Override
public Result checkRefuse(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动中不可审核拒绝");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动中不可撤销审核");
}
@Override
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result(Result.CODE_OK, "活动关闭成功");
}
@Override
public Result open(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动中不可开启");
}
@Override
public Result doing(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动中不可重复执行");
}
}
/**
* 活动状态;编辑中
*/
public class EditingState extends State {
@Override
public Result arraignment(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Check);
return new Result(Result.CODE_OK, "活动提审成功");
}
@Override
public Result checkPass(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "编辑中不可审核通过");
}
@Override
public Result checkRefuse(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "编辑中不可审核拒绝");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "编辑中不可撤销审核");
}
@Override
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result(Result.CODE_OK, "活动关闭成功");
}
@Override
public Result open(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "非关闭活动不可开启");
}
@Override
public Result doing(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "编辑中活动不可执行活动中变更");
}
}
/**
* 活动状态;活动开启
*/
public class OpenState extends State {
@Override
public Result arraignment(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动开启不可提审");
}
@Override
public Result checkPass(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动开启不可审核通过");
}
@Override
public Result checkRefuse(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动开启不可审核拒绝");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动开启不可撤销审核");
}
@Override
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result(Result.CODE_OK, "活动关闭完成");
}
@Override
public Result open(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "活动不可重复开启");
}
@Override
public Result doing(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Doing);
return new Result(Result.CODE_OK, "活动变更活动中完成");
}
}
/**
* 活动状态;审核通过
*/
public class PassState extends State {
@Override
public Result arraignment(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "已审核状态不可重复提审");
}
@Override
public Result checkPass(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "已审核状态不可重复审核");
}
@Override
public Result checkRefuse(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Refuse);
return new Result(Result.CODE_OK, "活动审核拒绝完成");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "审核通过不可撤销(可先拒绝审核)");
}
@Override
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result(Result.CODE_OK, "活动审核关闭完成");
}
@Override
public Result open(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "非关闭活动不可开启");
}
@Override
public Result doing(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Doing);
return new Result(Result.CODE_OK, "活动变更活动中完成");
}
}
/**
* 活动状态;审核拒绝
*/
public class RefuseState extends State {
@Override
public Result arraignment(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "已审核状态不可重复提审");
}
@Override
public Result checkPass(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "已审核状态不可重复审核");
}
@Override
public Result checkRefuse(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Refuse);
return new Result(Result.CODE_OK, "活动审核拒绝不可重复审核");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Editing);
return new Result(Result.CODE_OK, "撤销审核完成");
}
@Override
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result(Result.CODE_OK, "活动审核关闭完成");
}
@Override
public Result open(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "非关闭活动不可开启");
}
@Override
public Result doing(String activityId, Enum currentStatus) {
return new Result(Result.CODE_ERROR, "审核拒绝不可执行活动为进行中");
}
}
/**
* 状态处理服务
*/
public class StateHandler {
private final Map stateMap = new ConcurrentHashMap();
public StateHandler() {
// 待审核
stateMap.put(Status.Check, new CheckState());
// 已关闭
stateMap.put(Status.Close, new CloseState());
// 活动中
stateMap.put(Status.Doing, new DoingState());
// 编辑中
stateMap.put(Status.Editing, new EditingState());
// 已开启
stateMap.put(Status.Open, new OpenState());
// 审核通过
stateMap.put(Status.Pass, new PassState());
// 审核拒绝
stateMap.put(Status.Refuse, new RefuseState());
}
public Result arraignment(String activityId, Enum currentStatus) {
return stateMap.get(currentStatus).arraignment(activityId, currentStatus);
}
public Result checkPass(String activityId, Enum currentStatus) {
return stateMap.get(currentStatus).checkPass(activityId, currentStatus);
}
public Result checkRefuse(String activityId, Enum currentStatus) {
return stateMap.get(currentStatus).checkRefuse(activityId, currentStatus);
}
public Result checkRevoke(String activityId, Enum currentStatus) {
return stateMap.get(currentStatus).checkRevoke(activityId, currentStatus);
}
public Result close(String activityId, Enum currentStatus) {
return stateMap.get(currentStatus).close(activityId, currentStatus);
}
public Result open(String activityId, Enum currentStatus) {
return stateMap.get(currentStatus).open(activityId, currentStatus);
}
public Result doing(String activityId, Enum currentStatus) {
return stateMap.get(currentStatus).doing(activityId, currentStatus);
}
}
public class Client {
public static void main(String[] args) {
testEditing2Arraignment();
testEditing2Open();
testRefuse2Doing();
testRefuse2Revoke();
}
private static void testEditing2Arraignment() {
String activityId = "100001";
ActivityService.init(activityId, Status.Editing);
StateHandler stateHandler = new StateHandler();
Result result = stateHandler.arraignment(activityId, Status.Editing);
System.out.println("测试结果(编辑中To提审活动):" + JSON.toJSONString(result));
System.out.println("活动信息:" + JSON.toJSONString(ActivityService.queryActivityInfo(activityId)) + "状态:" + JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
}
private static void testEditing2Open() {
String activityId = "100001";
ActivityService.init(activityId, Status.Editing);
StateHandler stateHandler = new StateHandler();
Result result = stateHandler.open(activityId, Status.Editing);
System.out.println("测试结果(编辑中To开启活动):" + JSON.toJSONString(result));
System.out.println("活动信息:" + JSON.toJSONString(ActivityService.queryActivityInfo(activityId)) + "状态:" + JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
}
private static void testRefuse2Doing() {
String activityId = "100001";
ActivityService.init(activityId, Status.Refuse);
StateHandler stateHandler = new StateHandler();
Result result = stateHandler.doing(activityId, Status.Refuse);
System.out.println("测试结果(拒绝To活动中):" + JSON.toJSONString(result));
System.out.println("活动信息:" + JSON.toJSONString(ActivityService.queryActivityInfo(activityId)) + "状态:" + JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
}
private static void testRefuse2Revoke() {
String activityId = "100001";
ActivityService.init(activityId, Status.Refuse);
StateHandler stateHandler = new StateHandler();
Result result = stateHandler.checkRevoke(activityId, Status.Refuse);
System.out.println("测试结果(拒绝To撤审):" + JSON.toJSONString(result));
System.out.println("活动信息:" + JSON.toJSONString(ActivityService.queryActivityInfo(activityId)) + "状态:" + JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
}
}
状态模式的适用场景
- 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
- 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。
状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说在行为受状态约束的情况下可以使用状态模式,而且使用时对象的状态最好不要超过5个。
本文主要参考:
- 小傅哥的《重学Java模式》
- 《C语言中文网》设计模式的相关内容
- 《设计模式之禅》第二版 秦小波