设计模式的状态模式,就是把状态独立成一个类,代替传统复杂的if-else。
网上还有非常多关于状态模式的介绍,不过很多都是点到即止,例子我理解的也不是很清楚。设计模式只是一种思路,掌握好这个思路就可以,实现有非常多种方法。
接下来我有项目经典问题-审批流程,来使用下状态模式。
基本的审批流程如下: 提交表单 -> 一级审批 -> 二级审批 -> 结束
那对应的我也设置了四个状态: 提交表单状态、一级审批状态、二级审批状态、结束状态。
状态定义了三个动作: 同意并进入下一环节(agreeToNext)、驳回上一环节(backToBefore)、结束(finish)
接下来我先定义状态的父类,这里我用到了抽象类,而非接口,因为我想状态有很多通用属性。很多网上例子会把这些属性放到Context上下文里面,通过改变状态去修改这些属性,我觉得都可以。
此父类声明了很多状态的属性,以及定义了三个动作,但是我把结束动作方法给实现了,因为我觉得接收动作代码都是相同的。
/**
* 提交状态0->一级审批1->二级审批2 ->审批完成3
* 状态
*/
public abstract class Status {
/**
* 同意并进入下一环节
* @param task 任务
* @param msg 意见
* @param nextUser 下一环节处理人
*/
public abstract boolean agreeToNext(ApproveTask task, String msg, String nextUser);
/**
* 打回上一环节
* @param task 任务
* @param msg 意见
* @return
*/
public abstract boolean backToBefore(ApproveTask task, String msg);
//属性
String statusName;//状态名
String user;//操作用户
String suggest;//意见信息
String request;//申请信息
boolean operationFlag;//是否进行了操作
int statusId = -1;
boolean agreeFlag;//是否同意
boolean isFinish;//是否终止状态
int nextStatusId = -1;//下一环节 状态id
/**
* 构造方法
*/
public Status(String user,String request) {
this.user = user;
this.request = request;
}
/**
* 结束
* @param task 任务
* @param msg 意见
*/
public boolean finish(ApproveTask task,String msg,boolean agreeFlag){
System.out.println("环节结束 是否异常:"+agreeFlag);
task.getApproveStatusList().add(this);//放入审批链中
this.suggest = msg;
this.agreeFlag = agreeFlag;
this.nextStatusId = 3;
this.operationFlag = true;
//异常终止
FinishStatus finishStatus = new FinishStatus(this.user,msg,agreeFlag);
task.setStatus(finishStatus);
task.getApproveStatusList().add(finishStatus);
return true;
}
@Override
public String toString() {
return "状态名:"+statusName +" 状态id:"+statusId+" 下一环节id:"+
nextStatusId+" 操作用户:"+user
+" 是否进行了操作:"+operationFlag
+" 是否同意:"+agreeFlag
+" 申请信息:"+request
+" 意见信息:"+ suggest;
}
}
接下来是具体的状态类:
提交状态类
/**
* 提交状态0->一级审批1->二级审批2 ->审批完成3
*
* 此类是提交状态
*
*/
public class SubmitStatus extends Status{
public SubmitStatus(String user,String request) {
super(user,request);
this.statusName = "提交状态";
this.statusId = 0;
}
@Override
public boolean agreeToNext(ApproveTask task,String msg,String nextUser){
System.out.println("提交环节同意");
this.operationFlag = true;
this.agreeFlag = true;//
this.suggest = msg;
this.nextStatusId = statusId + 1;//下级状态
task.getApproveStatusList().add(this);//放入审批路径
task.setStatus(new FirstApproveStatus(nextUser,suggest));//设置下级审批,当前的意见成为下一审批人的申请信息
return true;
}
@Override
public boolean backToBefore(ApproveTask task,String msg){
System.out.println("提交环节,不能打回");
return false;
}
}
一级审批状态类:
/**
* 提交状态0->一级审批1->二级审批2 ->审批完成3
* 一级审批
*/
public class FirstApproveStatus extends Status{
/**
* 构造方法
*
* @param user
*/
public FirstApproveStatus(String user,String request) {
super(user,request);
this.statusName = "一级审批";
this.statusId = 1;
}
@Override
public boolean agreeToNext(ApproveTask task, String msg, String nextUser) {
System.out.println("一级审批同意");
this.agreeFlag = true;//
this.operationFlag = true;
this.suggest = msg;
this.nextStatusId = statusId + 1;//下级状态
task.getApproveStatusList().add(this);//放入审批路径
task.setStatus(new SecondApproveStatus(nextUser,this.suggest));//设置下级审批
return true;
}
@Override
public boolean backToBefore(ApproveTask task, String msg) {
System.out.println("一级审批回退");
this.agreeFlag = false;
this.operationFlag = true;
this.suggest = msg;
this.nextStatusId = statusId -1;
String beforeUserId = task.getApproveStatusList().get(task.getApproveStatusList().size() - 1).user;
task.getApproveStatusList().add(this);
task.setStatus(new SubmitStatus(beforeUserId,this.suggest));
return true;
}
}
二级审批状态类:
public class SecondApproveStatus extends Status {
/**
* 构造方法
*
* @param user
*/
public SecondApproveStatus(String user,String request) {
super(user,request);
this.statusName = "二级审批";
this.statusId = 2;
}
@Override
public boolean agreeToNext(ApproveTask task, String msg, String nextUser) {
System.out.println("二级审批同意");
/* this.agreeFlag = true;//
this.suggest = msg;
this.nextStatusId = statusId + 1;//下级状态
task.getApproveStatusList().add(this);//放入审批路径
Status finishStatus = new FinishStatus(this.user,this.suggest,true);
task.setStatus(finishStatus);//设置下级审批
task.getApproveStatusList().add(finishStatus);//放入审批路径
*/
this.finish(task,msg,true);
return true;
}
@Override
public boolean backToBefore(ApproveTask task, String msg) {
System.out.println("二级审批回退");
this.agreeFlag = false;
this.suggest = msg;
this.nextStatusId = statusId -1;
this.operationFlag = true;
String beforeUserId = task.getApproveStatusList().get(task.getApproveStatusList().size() - 1).user;
task.getApproveStatusList().add(this);
task.setStatus(new FirstApproveStatus(beforeUserId,this.suggest));
return true;
}
}
结束状态类:
/**
* 提交状态0->一级审批1->二级审批2 ->审批完成3
* 一级审批
*/
public class FirstApproveStatus extends Status{
/**
* 构造方法
*
* @param user
*/
public FirstApproveStatus(String user,String request) {
super(user,request);
this.statusName = "一级审批";
this.statusId = 1;
}
@Override
public boolean agreeToNext(ApproveTask task, String msg, String nextUser) {
System.out.println("一级审批同意");
this.agreeFlag = true;//
this.operationFlag = true;
this.suggest = msg;
this.nextStatusId = statusId + 1;//下级状态
task.getApproveStatusList().add(this);//放入审批路径
task.setStatus(new SecondApproveStatus(nextUser,this.suggest));//设置下级审批
return true;
}
@Override
public boolean backToBefore(ApproveTask task, String msg) {
System.out.println("一级审批回退");
this.agreeFlag = false;
this.operationFlag = true;
this.suggest = msg;
this.nextStatusId = statusId -1;
String beforeUserId = task.getApproveStatusList().get(task.getApproveStatusList().size() - 1).user;
task.getApproveStatusList().add(this);
task.setStatus(new SubmitStatus(beforeUserId,this.suggest));
return true;
}
}
接下来是任务类,也就是很多网络例子的Context上下文 或环境。
这个类有当前的状态、还有整个审批状态流的属性,还有提供对外的 同意、驳回、拒绝等操作,外部只需要对此类进行操作即可。
import java.util.ArrayList;
import java.util.List;
/**
* 审批任务 相当于 状态模式的Context 环境
*
*/
public class ApproveTask {
private Status status;//当前的状态
private List approveStatusList = new ArrayList<>();//审批操作人 此处可以扩展
/**
* 任务 构造函数
*/
public ApproveTask(String user){
this.status = new SubmitStatus(user,null);
}
/**
* 同意 要写同意意见
* @param msg 同意意见
*/
public void agree(String msg,String nextUser){
status.agreeToNext(this,msg,nextUser);
}
/**
* 驳回
* @param msg
*/
public void back(String msg){
status.backToBefore(this,msg);
}
public void refuse(String msg){
status.finish(this,msg,false);
}
/**
* 打印审批路径
*/
public void showApprovePath(){
approveStatusList.stream().forEach(System.out::println);
}
//getter and setter
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public List getApproveStatusList() {
return approveStatusList;
}
public void setApproveStatusList(List approveStatusList) {
this.approveStatusList = approveStatusList;
}
}
测试方法1(正常二级审批流程):
public static void normal(){
System.out.println("---------正常流程----------");
ApproveTask approveTask = new ApproveTask("小红");//小红新建个审批任务
approveTask.agree("由于工作需要,申请对工程机进行使用 3天","小明");//小红写申请书,提交给 小明
approveTask.agree("小红需要对工程师进行使用,初步决定可以","小亮");//小明一级审批同意,并发送给小亮
approveTask.agree("情况属实,可以批准",null);//小亮审批同意
System.out.println();
System.out.println("----整体审批路径如下----");
approveTask.showApprovePath();
}
运行结果:
---------正常流程----------
提交环节同意
一级审批同意
二级审批同意
环节结束 是否异常:true
----整体审批路径如下----
状态名:提交状态 状态id:0 下一环节id:1 操作用户:小红 是否进行了操作:true 是否同意:true 申请信息:null 意见信息:由于工作需要,申请对工程机进行使用 3天
状态名:一级审批 状态id:1 下一环节id:2 操作用户:小明 是否进行了操作:true 是否同意:true 申请信息:由于工作需要,申请对工程机进行使用 3天 意见信息:小红需要对工程师进行使用,初步决定可以
状态名:二级审批 状态id:2 下一环节id:3 操作用户:小亮 是否进行了操作:true 是否同意:true 申请信息:小红需要对工程师进行使用,初步决定可以 意见信息:情况属实,可以批准
状态名:结束环境 状态id:-1 下一环节id:-1 操作用户:小亮 是否进行了操作:true 是否同意:true 申请信息:情况属实,可以批准 意见信息:null
测试方法2(驳回例子):
public static void back(){
System.out.println("---------驳回流程--------");
System.out.println("新建任务");
ApproveTask approveTask = new ApproveTask("小红");//小红新建个审批任务
System.out.println("现在的任务状态:"+approveTask.getStatus());
approveTask.agree("由于工作需要,申请对工程机进行使用 3天","小明");//小红写申请书,提交给 小明
System.out.println("现在的任务状态:"+approveTask.getStatus());
approveTask.agree("小红需要对工程师进行使用,初步决定可以","小亮");//小明一级审批同意,并发送给小亮
System.out.println("现在的任务状态:"+approveTask.getStatus());
approveTask.back("不行呀,请再检查检查");//小亮 二级审批不同意
System.out.println("现在的任务状态:"+approveTask.getStatus());
approveTask.agree("已经检查过库存了,确定可以","小亮");//小明一级审批再次同意
System.out.println("现在的任务状态:"+approveTask.getStatus());
approveTask.agree("情况属实,可以批准",null);//小亮审批同意
System.out.println();
System.out.println("----整体审批路径如下----");
approveTask.showApprovePath();
}
运行结果:
---------驳回流程--------
新建任务
现在的任务状态:状态名:提交状态 状态id:0 下一环节id:-1 操作用户:小红 是否进行了操作:false 是否同意:false 申请信息:null 意见信息:null
提交环节同意
现在的任务状态:状态名:一级审批 状态id:1 下一环节id:-1 操作用户:小明 是否进行了操作:false 是否同意:false 申请信息:由于工作需要,申请对工程机进行使用 3天 意见信息:null
一级审批同意
现在的任务状态:状态名:二级审批 状态id:2 下一环节id:-1 操作用户:小亮 是否进行了操作:false 是否同意:false 申请信息:小红需要对工程师进行使用,初步决定可以 意见信息:null
二级审批回退
现在的任务状态:状态名:一级审批 状态id:1 下一环节id:-1 操作用户:小明 是否进行了操作:false 是否同意:false 申请信息:不行呀,请再检查检查 意见信息:null
一级审批同意
现在的任务状态:状态名:二级审批 状态id:2 下一环节id:-1 操作用户:小亮 是否进行了操作:false 是否同意:false 申请信息:已经检查过库存了,确定可以 意见信息:null
二级审批同意
环节结束 是否异常:true
----整体审批路径如下----
状态名:提交状态 状态id:0 下一环节id:1 操作用户:小红 是否进行了操作:true 是否同意:true 申请信息:null 意见信息:由于工作需要,申请对工程机进行使用 3天
状态名:一级审批 状态id:1 下一环节id:2 操作用户:小明 是否进行了操作:true 是否同意:true 申请信息:由于工作需要,申请对工程机进行使用 3天 意见信息:小红需要对工程师进行使用,初步决定可以
状态名:二级审批 状态id:2 下一环节id:1 操作用户:小亮 是否进行了操作:true 是否同意:false 申请信息:小红需要对工程师进行使用,初步决定可以 意见信息:不行呀,请再检查检查
状态名:一级审批 状态id:1 下一环节id:2 操作用户:小明 是否进行了操作:true 是否同意:true 申请信息:不行呀,请再检查检查 意见信息:已经检查过库存了,确定可以
状态名:二级审批 状态id:2 下一环节id:3 操作用户:小亮 是否进行了操作:true 是否同意:true 申请信息:已经检查过库存了,确定可以 意见信息:情况属实,可以批准
状态名:结束环境 状态id:-1 下一环节id:-1 操作用户:小亮 是否进行了操作:true 是否同意:true 申请信息:情况属实,可以批准 意见信息:null
小结:
以上就是状态模式模拟审批流程的简单例子。
当然,有很多优化的地方,比如 驳回可以选择驳回环节、任务类需要可以进行序列化和反序列化,可以把任务结果保存入数据库中,并且可以根据数据库中存入的值还原成任务类等操作。