亲宝软件园·资讯

展开

设计模式之状态模式实战

WeJan1 人气:1
[本文原文链接地址:http://nullpointer.pwhttps://img.qb5200.com/download-x/design-patterns-state.html](http://nullpointer.pwhttps://img.qb5200.com/download-x/design-patterns-state.html) 本文以运营活动状态转换为例,结合 Spring 演示状态模式的实践应用。 类型:行为型模式 意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。 主要解决:一个对象存在多个状态,每个状态行为不同,状态可以相互转换。 使用场景:1、行为随状态改变而改变的场景。 2、减少 switch..case 以及 if...else [设计模式系列文章目录 ](http://nullpointer.pwhttps://img.qb5200.com/download-x/design-patterns.html) ## 角色 - State:抽象状态角色,负责对象状态定义,并且封装环境角色以实现状态切换。 - Context:环境角色,定义客户端需要的接口,并且负责具体状态的切换。 - ConcreteState:具体状态角色,当前状态要做的事情,以及当前状态如何转换其他状态。 ## UML ![](http://www.plantuml.com/plantuml/svg/LSx12O0m40J0_rLnJqNIWOXW2LPmnWCVCM9k1K7iNIKe-DxPPLk396np81_4ZBibGdVmGSHSST9rKqDHqaaaWo691sVQGw0tVDmaSGoQsJVaaq9VzIJl-EAQtAQSrixzFRKQn_lK1G00) ## 实战 本文以运营活动状态为例,结合 Spring 演示状态模式的实践应用。 运营活动创建初始状态为草稿状态,编辑好活动之后,运营会后台启用活动,此时活动状态为已启用; 当达到活动开始时间时,定时任务会将活动状态置为进行中; 当达到活动结束时间时,定时任务会将活动状态置为已结束。 进行中的活动也可能会因为某些原因需要手动停用,此时活动状态置为已停用。 状态之间有着严格的前置校验,比如草稿状态可以继续保存为草稿,也可以进行启动,但不能直接切换为进行中,可以直接编辑切换回草稿箱状态;比如已停用的状态只有在启用之后才能被置为进行中。 活动状态的切换约束如下图: | 新状态→
当前状态↓ | 草稿箱 | 已启用 | 进行中 | 已停用 | 已结束 | | :---------------------: | :----: | :----: | :----: | :----: | :----: | | 草稿箱 | ✅ | ✅ | ❌ | ❌ | ❌ | | 已启用 | ✅ | ❌ | ✅ | ✅ | ❌ | | 进行中 | ❌ | ❌ | ❌ | ✅ | ✅ | | 已停用 | ❌ | ✅ | ❌ | ❌ | ❌ | | 已结束 | ❌ | ❌ | ❌ | ❌ | ❌ | 如果不采取状态模式,可能写出的代码就是不断使用 if 判断前置状态是否符合规则,当增加了新的状态,需要改动判断的地方,从而可能引入了 Bug。 ### 本文示例 UML 图 ![](http://www.plantuml.com/plantuml/svg/vLR1Ri8m3BtxAonnwJJr2q0Jqs3Ipdo1svejKabGOofGuTyfGOMswhAC8pqcUNxnUtQipArG8RjD3fHOAIWLJ7Eo5jzJKQMImqf862k0oMthmsZXlI1rrm28hrWQbQ5bwO6ZFu9VN73L977wgdU_kK0vR3dg7oR6v4mQBPMyA6XzPx_H_XR2cfASm_7Edd1ufkp_-DTAA_ipX3y1T2lHE5VLL76lFjHUJGSBuOuYJzWrnM1lmnmDyZ7GlGSySmgQ5hvm3FJLSobUkkH69NbrkNPKYXTNnb5f_dJG9vSC_M5luhVkg8Vk19yTutXWslbGhGdXWzrVbVVALYVwSAtgmPnrLlyupW00) ## 示例代码 ### 定义抽象状态角色 ```java public abstract class ActivityState { // 抽象状态角色需要持有环境上下文对象 protected ActivityContext activityContext; public void setActivityContext(ActivityContext activityContext) { this.activityContext = activityContext; } public abstract Integer type(); /** * 判断是否是当前状态 */ protected boolean isSameStatus(Activity activity) { return type().equals(activity.getStatus()); } /** * 保存草稿 */ public abstract boolean saveDraft(Activity activity); /** * 启用 */ public abstract boolean enable(Activity activity); /** * 开始 */ public abstract boolean start(Activity activity); /** * 停用 */ public abstract boolean disable(Activity activity); /** * 停止 */ public abstract boolean finish(Activity activity); } ``` ### 定义环境角色 ```java public class ActivityContext { // 持有抽象状态角色引用 private ActivityState activityState; public void setActivityState(ActivityState activityState) { this.activityState = activityState; this.activityState.setActivityContext(this); } public boolean saveDraft(Activity activity) { // 委托具体的状态角色 return this.activityState.saveDraft(activity); } public boolean enable(Activity activity) { return this.activityState.enable(activity); } public boolean start(Activity activity) { return this.activityState.start(activity); } public boolean disable(Activity activity) { return this.activityState.disable(activity); } public boolean finish(Activity activity) { return this.activityState.finish(activity); } } ``` ### 定义具体状态角色 因为本文示例具体状态角色有很多,因此只列举一个开启状态角色举例参考,更多代码可以参考本文对应的 GitHub 示例代码 ```java @Component public class ActivityEnableState extends ActivityState { @Resource private ActivityDraftState activityDraftState; @Resource private ActivityStartState activityStartState; @Resource private ActivityDisableState activityDisableState; @Override public Integer type() { return ActivityStateEnum.ENABLE.getCode(); } @Override public boolean saveDraft(Activity activity) { super.activityContext.setActivityState(activityDraftState); return activityContext.saveDraft(activity); } @Override public boolean enable(Activity activity) { // 如果当前状态已经是 enable 了,则无法再次 enable if (isSameStatus(activity)) { return false; } activity.setStatus(type()); //TODO 更新数据库 return true; } @Override public boolean start(Activity activity) { super.activityContext.setActivityState(activityStartState); return activityContext.start(activity); } @Override public boolean disable(Activity activity) { super.activityContext.setActivityState(activityDisableState); return activityContext.disable(activity); } @Override public boolean finish(Activity activity) { // 非进行中的活动状态,不允许直接进行 finish return false; } } ``` ### 封装具体状态实例工厂 状态角色应该是单例的,结合 Spring 与工厂模式对实例进行封装,方便根据数据库的 status 值获取对应的状态角色实例。 ```java @Component public class ActivityStateFactory implements ApplicationContextAware { public static final Map

加载全部内容

相关教程
猜你喜欢
用户评论