文章目录
状态模式
- 状态模式
- 状态模式实战.
- 不使用状态模式的写法
- 使用状态模式的写法
状态模式的情景: 状态模式用于一个行为下的多种状态的变更. 例如活动的审核 , 上线 ,下线状态等.
状态模式实战.模拟活动的编辑 ,上线 , 审批拒绝, 审批通过等. 并且有些状态的流转是不可行的, 比如编辑中, 到下线.
创建tutorials-22.0-1 模块. 定义状态的枚举
package com.thc.design;
/**
* 类名称:Status
* 类描述: 活动状态枚举
*
* 创建时间:2022/4/3 10:31
*/
public enum Status {
// 1创建编辑、2待审核、3审核通过(任务扫描成活动中)、4审核拒绝(可以撤审到编辑状态)、5活动中、6活动关闭、7活动开启(任务扫描成活动中)
Editing, Check, Pass, Refuse, Doing, Close, Open
}
定义活动的实体类
package com.thc.design;
import lombok.Data;
import java.util.Date;
/**
* 类名称:ActivityInfo
* 类描述: 活动信息类
*
* 创建时间:2022/4/3 10:30
*/
@Data
public class ActivityInfo {
// 活动id
private String activityId;
// 活动名称
private String activityName;
// 活动状态
private Enum status;
private Date beginTime;
private Date endTime;
}
创建活动变化的类
package com.thc.design;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 类名称:ActivityService
* 类描述: 活动服务业务类
*
* 创建时间:2022/4/3 10:34
*/
public class ActivityService {
private static Map statusMap = 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());
statusMap.put(activityId, status);
}
// 查询活动信息
public static ActivityInfo queryActivityInfo(String activityId){
// 模拟查询活动信息
ActivityInfo activityInfo = new ActivityInfo();
activityInfo.setActivityId(activityId);
activityInfo.setActivityName("早起学习打卡领奖活动");
activityInfo.setStatus(statusMap.get(activityId));
activityInfo.setBeginTime(new Date());
activityInfo.setEndTime(new Date());
return activityInfo;
}
public static Enum queryActivityStatus(String activityId) {
return statusMap.get(activityId);
}
/**
* 执行状态变更
* @param activityId
* @param beforeStatus
* @param afterStatus
*/
public static synchronized void execStatus(String activityId, Enum beforeStatus, Enum afterStatus) {
if (! beforeStatus.equals(statusMap.get(activityId))) return;
statusMap.put(activityId, afterStatus);
}
}
不使用状态模式的写法
创建 tutorials-22.0-2模块 创建结果返回对象
package com.thc.design;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 类名称:Result
* 类描述:执行结果
*
* 创建时间:2022/4/3 10:51
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Result {
// 编码
private String code;
// 描述
private String info;
}
创建ActivityExecStatusController 类, 用于状态的执行.
public class ActivityExecStatusController {
public Result execStatus(String activityId, Enum beforeStatus, Enum afterStatus) {
// 编辑变为 提审 关闭
if (Status.Editing.equals(beforeStatus)) {
if (Status.Check.equals(afterStatus) || Status.Close.equals(afterStatus)) {
ActivityService.execStatus(activityId, beforeStatus, afterStatus);
return new Result("0000", "状态变更成功");
} else {
// 只能由状态编辑变为提审或者关闭, 其他状态不允许变更.
return new Result("0001", "状态变更拒绝");
}
}
// 2. 审核通过 -> 拒绝、关闭、活动中
if (Status.Pass.equals(beforeStatus)) {
if (Status.Refuse.equals(afterStatus) || Status.Doing.equals(afterStatus) || Status.Close.equals(afterStatus)) {
ActivityService.execStatus(activityId, beforeStatus, afterStatus);
return new Result("0000", "变更状态成功");
} else {
return new Result("0001", "变更状态拒绝");
}
}
// 3. 审核拒绝 -> 撤审、关闭
if (Status.Refuse.equals(beforeStatus)) {
if (Status.Editing.equals(afterStatus) || Status.Close.equals(afterStatus)) {
ActivityService.execStatus(activityId, beforeStatus, afterStatus);
return new Result("0000", "变更状态成功");
} else {
return new Result("0001", "变更状态拒绝");
}
}
// 4. 活动中 -> 关闭
if (Status.Doing.equals(beforeStatus)) {
if (Status.Close.equals(afterStatus)) {
ActivityService.execStatus(activityId, beforeStatus, afterStatus);
return new Result("0000", "变更状态成功");
} else {
return new Result("0001", "变更状态拒绝");
}
}
// 5. 活动关闭 -> 开启
if (Status.Close.equals(beforeStatus)) {
if (Status.Open.equals(afterStatus)) {
ActivityService.execStatus(activityId, beforeStatus, afterStatus);
return new Result("0000", "变更状态成功");
} else {
return new Result("0001", "变更状态拒绝");
}
}
// 6. 活动开启 -> 关闭
if (Status.Open.equals(beforeStatus)) {
if (Status.Close.equals(afterStatus)) {
ActivityService.execStatus(activityId, beforeStatus, afterStatus);
return new Result("0000", "变更状态成功");
} else {
return new Result("0001", "变更状态拒绝");
}
}
return new Result("0001", "非可处理的活动状态变更");
}
}
测试类
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@Test
public void test() {
// 初始化数据
String activityId = "10001";
ActivityService.init(activityId, Status.Editing);
ActivityExecStatusController activityExecStatusController = new ActivityExecStatusController();
// 测试从编辑中,变为审批拒绝
Result resultRefuse = activityExecStatusController.execStatus(activityId, Status.Editing, Status.Refuse);
logger.info("测试结果 (编辑中 to 审批拒绝 ): {}", JSON.toJSONString(resultRefuse));
Result resultCheck = activityExecStatusController.execStatus(activityId, Status.Editing, Status.Check);
logger.info("测试结果: 编辑中 to 提交审核 : {}", JSON.toJSONString(resultCheck));
}
}
结果如下
13:55:21.513 [main] INFO com.thc.design.test.ApiTest - 测试结果 (编辑中 to 审批拒绝 ): {"code":"0001","info":"状态变更拒绝"}
13:55:21.517 [main] INFO com.thc.design.test.ApiTest - 测试结果: 编辑中 to 提交审核 : {"code":"0000","info":"状态变更成功"}
使用状态模式的写法
使用状态模式, 进行state的抽象. 每一种状态由一个实体类来维护. 每一种状态到下一个状态, 都是在方法中控制, 无需写if else 最后是StateHandler 对状态的流程统一的处理.
定义tutorials-22.0-3模块 创建状态抽象类 . 里面定义了状态的各个方法.
package com.thc.design;
/**
* 类名称:State
* 类描述: 定义状态抽象类
*
* 创建时间:2022/4/3 11:11
*/
public abstract class State {
/**
* 活动提审
* @param activityId
* @param currentStatus
* @return
*/
public abstract Result arraignment(String activityId, Enum currentStatus);
/**
* 审核通过
* @param activityId
* @param currentStatus
* @return
*/
public abstract Result checkPass(String activityId, Enum currentStatus);
/**
* 审核拒绝
* @param activityId
* @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);
}
定义各个状态的抽象类的实现 . 编辑状态实现类 :
package com.thc.design.impl;
import com.thc.design.ActivityService;
import com.thc.design.Result;
import com.thc.design.State;
import com.thc.design.Status;
/**
* 类名称:EditingState
* 类描述: 编辑中
*
* @author: https://javaweixin6.blog.csdn.net/
* 创建时间:2022/4/3 11:19
*/
public class EditingState extends State {
@Override
public Result arraignment(String activityId, Enum currentStatus) {
// 活动编辑状态 变为提审状态
ActivityService.execStatus(activityId, currentStatus, Status.Check);
return new Result("0000", "活动提审成功");
}
public Result checkPass(String activityId, Enum currentStatus) {
return new Result("0001", "编辑中不可审核通过");
}
public Result checkRefuse(String activityId, Enum currentStatus) {
return new Result("0001", "编辑中不可审核拒绝");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
return new Result("0001", "编辑中不可撤销审核");
}
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result("0000", "活动关闭成功");
}
public Result open(String activityId, Enum currentStatus) {
return new Result("0001", "非关闭活动不可开启");
}
public Result doing(String activityId, Enum currentStatus) {
return new Result("0001", "编辑中活动不可执行活动中变更");
}
}
待审核
/**
* 类名称:CheckState 待审核
* 创建时间:2022/4/3 11:23
*/
public class CheckState extends State {
public Result arraignment(String activityId, Enum currentStatus) {
return new Result("0001", "待审核状态不可重复提审");
}
@Override
public Result checkPass(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Pass);
return new Result("0000", "活动审核通过完成");
}
@Override
public Result checkRefuse(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Refuse);
return new Result("0000", "活动审核拒绝完成");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Editing);
return new Result("0000", "活动审核撤销回到编辑中");
}
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result("0000", "活动审核关闭完成");
}
public Result open(String activityId, Enum currentStatus) {
return new Result("0001", "非关闭活动不可开启");
}
public Result doing(String activityId, Enum currentStatus) {
return new Result("0001", "待审核活动不可执行活动中变更");
}
}
PassState 审核通过
public class PassState extends State {
public Result arraignment(String activityId, Enum currentStatus) {
return new Result("0001", "已审核状态不可重复提审");
}
public Result checkPass(String activityId, Enum currentStatus) {
return new Result("0001", "已审核状态不可重复审核");
}
public Result checkRefuse(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Refuse);
return new Result("0000", "活动审核拒绝完成");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
return new Result("0001", "审核通过不可撤销(可先拒绝审核)");
}
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result("0000", "活动审核关闭完成");
}
public Result open(String activityId, Enum currentStatus) {
return new Result("0001", "非关闭活动不可开启");
}
public Result doing(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Doing);
return new Result("0000", "活动变更活动中完成");
}
}
活动开启
public class OpenState extends State {
public Result arraignment(String activityId, Enum currentStatus) {
return new Result("0001", "活动开启不可提审");
}
public Result checkPass(String activityId, Enum currentStatus) {
return new Result("0001", "活动开启不可审核通过");
}
public Result checkRefuse(String activityId, Enum currentStatus) {
return new Result("0001", "活动开启不可审核拒绝");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
return new Result("0001", "活动开启不可撤销审核");
}
public Result close(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Close);
return new Result("0000", "活动关闭完成");
}
public Result open(String activityId, Enum currentStatus) {
return new Result("0001", "活动不可重复开启");
}
public Result doing(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Doing);
return new Result("0000", "活动变更活动中完成");
}
}
活动关闭
/**
* 活动状态;活动关闭
*/
public class CloseState extends State {
public Result arraignment(String activityId, Enum currentStatus) {
return new Result("0001", "活动关闭不可提审");
}
public Result checkPass(String activityId, Enum currentStatus) {
return new Result("0001", "活动关闭不可审核通过");
}
public Result checkRefuse(String activityId, Enum currentStatus) {
return new Result("0001", "活动关闭不可审核拒绝");
}
@Override
public Result checkRevoke(String activityId, Enum currentStatus) {
return new Result("0001", "活动关闭不可撤销审核");
}
public Result close(String activityId, Enum currentStatus) {
return new Result("0001", "活动关闭不可重复关闭");
}
public Result open(String activityId, Enum currentStatus) {
ActivityService.execStatus(activityId, currentStatus, Status.Open);
return new Result("0000", "活动开启完成");
}
public Result doing(String activityId, Enum currentStatus) {
return new Result("0001", "活动关闭不可变更活动中");
}
}
状态处理服务 对所有的状态进行map
public class StateHandler {
private Map stateMap = new ConcurrentHashMap();
// 使用map 封装所有的情况.
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);
}
}
对状态服务的统一控制中心, 在构造函数中提供了所有状态和实现的具体关联. 放到map数据结构.
测试类 :
import com.alibaba.fastjson.JSON;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 类名称:ApiTest
* 创建时间:2022/4/3 11:36
*/
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@Test
public void test_Editing2Arraignment() {
String activityId = "100001";
ActivityService.init(activityId, Status.Editing);
StateHandler stateHandler = new StateHandler();
Result result = stateHandler.arraignment(activityId, Status.Editing);
logger.info("测试结果 (编辑中 to 提审活动 ) : {}", JSON.toJSONString(result));
logger.info("活动信息 : {} 状态 :{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)) ,
JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus())
);
}
@Test
public void test_Editing2Open() {
String activityId = "100001";
ActivityService.init(activityId, Status.Editing);
StateHandler stateHandler = new StateHandler();
Result result = stateHandler.open(activityId, Status.Editing);
logger.info("测试结果 (编辑中 to 开启活动 ) : {}", JSON.toJSONString(result));
logger.info("活动信息 : {} 状态 :{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)) ,
JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus())
);
}
}
测试了由编辑中到提审活动. 编辑中到开启活动. 结果如下 : 编辑到提审成功. 编辑到开启失败 .
14:51:15.062 [main] INFO com.thc.design.ApiTest - 测试结果 (编辑中 to 提审活动 ) : {"code":"0000","info":"活动提审成功"}
14:51:15.080 [main] INFO com.thc.design.ApiTest - 活动信息 : {"activityId":"100001","activityName":"早起学习打卡领奖活动","beginTime":1648968675068,"endTime":1648968675068,"status":"Check"} 状态 :"Check"
14:52:13.181 [main] INFO com.thc.design.ApiTest - 测试结果 (编辑中 to 开启活动 ) : {"code":"0001","info":"非关闭活动不可开启"}
14:52:13.197 [main] INFO com.thc.design.ApiTest - 活动信息 : {"activityId":"100001","activityName":"早起学习打卡领奖活动","beginTime":1648968733186,"endTime":1648968733186,"status":"Editing"} 状态 :"Editing"
使用状态模式后, 省去了 if else. 代码结构更加清晰, 但缺点是使用的较多. 每个状态类都会去写所有的状态方法, 需要一定的时间成本.