- 工作流技术(Workflow) 是工作流程的计算模型,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示,并对其实施计算。工作流要解决的主要问题是:为实现某个业务目标,在多个参与者之间,利用计算机,按某种预定规则自动传递文档、信息或是任务。
- 简单地说,工作流就是对工作流程及其各操作步骤之间业务规则的抽象、概括、描述。比如在企业OA系统中我们常用的请假流程,报销流程等等各种审批流程。
- 对于简单的业务而言,流程控制不会太复杂,可以使用状态模式(State Pattern)来辅助进行流程控制。因为大部分的流程都是状态驱动的!
假设有这样的“请假流程”的场景:某位程序员提出请假申请,先由项目经理审批,如果项目经理不同意,则流程结束;如果项目经理同意,再看请假天数是否超过3天,如果在项目经理审批权限内(3天),则审批流程也直接结束,否则交给部门经理;部门经理审核后无论是否同意,流程都直接结束。流程图如下:
在实际开发中,如果不考虑使用工作流框架,自己实现整个流程的过程简单描述如下:
1)UI操作:请假人提交请假单,提出申请
2)后台处理:保存请假单数据到数据库,为项目经理新建一个工作,把工作信息保存到数据库
3)UI操作:项目经理登录系统,获取自己的工作列表
4)后台处理:从数据库中查询相应的工作列表
5)UI操作:项目经理完成审核工作,提交保存
6)后台处理:处理项目经理的审核业务,保存审核信息到数据库。同时判断后续的工作,如果是需要人员参与的,则为参与工作的下一个人员创建工作,把工作信息保存到数据库
7)UI操作:部门经理登录系统,获取自己的工作列表,重复步骤3
8)后台处理:从数据库中查询相应的工作列表,重复步骤4
9)UI操作:部门经理完成审核工作,提交保存,重复步骤5
10)后台处理:类似步骤6
使用状态模式实现工作流思路:
- 仔细分析上面的流程图和请假流程的运行过程,把请假单在流程中的各个状态分析出来,我们发现,整个流程完全可以看成是状态驱动的!
- 在上述流程中,“请假单”大致有如下状态:等待项目经理审核、等待部门经理审核、审核结束。
- 既然可以把流程看做是状态驱动的,那么就可以自然地使用状态模式,每当相应的工作人员完成工作,请求流程响应的时候,流程处理对象会根据当前所处的状态,把流程处理委托给相应的状态对象去处理。
为了简单起见,本例不采用数据库保存状态数据(实际开发中通常使用数据库持久化状态信息),直接通过控制台接收数据,模拟一个请假流程,demo如下:
- 状态处理机
package com.zpc.test.statepattern;
/**
* 状态处理机,相当于状态模式中的Context(上下文)
*/
public class StateMachine {
/**
* 持有一个状态对象
*/
private State state;
/**
* 流程处理需要的业务数据对象
*/
private Object businessObj;
public void doWork(){
//转调相应的状态对象真正完成功能处理
this.state.doWork(this);
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public Object getBusinessObj() {
return businessObj;
}
public void setBusinessObj(Object businessObj) {
this.businessObj = businessObj;
}
}
- 状态接口
package com.zpc.test.statepattern;
/**
* 状态接口
*/
public interface State {
/**
* 执行状态对应的处理功能
*
* @param context 上下文实例
*/
void doWork(StateMachine context);
}
- 业务模型
package com.zpc.test.statepattern;
/**
* 请假单的业务模型
*/
public class LeaveRequestModel {
/**
* 请假人
*/
private String user;
/**
* 请假开始日期
*/
private String dateBegin;
/**
* 请假天数
*/
private Integer leaveDays;
/**
* 审核结果
*/
private String result;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getDateBegin() {
return dateBegin;
}
public void setDateBegin(String dateBegin) {
this.dateBegin = dateBegin;
}
public Integer getLeaveDays() {
return leaveDays;
}
public void setLeaveDays(Integer leaveDays) {
this.leaveDays = leaveDays;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
- 业务状态机
package com.zpc.test.statepattern;
/**
* 虽然这里并不需要扩展功能,但是还是继承一下状态机,表示可以添加自己的处理
*/
public class LeaveRequestContext extends StateMachine {
}
- 业务状态
package com.zpc.test.statepattern;
/**
* 虽然这里并不需要扩展功能,但是还是继承一下状态,表示可以添加自己的处理
*/
public interface LeaveRequestState extends State {
}
- 项目经理审核状态类
package com.zpc.test.statepattern;
import java.util.Scanner;
public class ProjectManagerState implements LeaveRequestState {
@Override
public void doWork(StateMachine context) {
//先提取业务对象
LeaveRequestModel businessObj = (LeaveRequestModel) context.getBusinessObj();
System.out.println("项目经理审核中。。。");
//模拟用户界面,从控制台读取数据
System.out.println(businessObj.getUser() + "申请从" + businessObj.getDateBegin() + "开始请假" + businessObj.getLeaveDays() + "天,请项目经理审核(1同意,2不同意):");
Scanner scanner = new Scanner(System.in);
if (scanner.hasNext()) {
int a = scanner.nextInt();
String res = "不同意";
if (a == 1) {
res = "同意";
}
businessObj.setResult("项目经理审核结果:" + res);
//根据选择的结果和条件选择下一步
if (a == 1) {
if (businessObj.getLeaveDays() > 3) {
//3天以上的假项目经理同意了则交由部门经理审核
context.setState(new DepManagerState());
context.doWork();
} else {
//3天以内的假项目经理直接做主,就不用交给部门经理了,转向审核结束状态
context.setState(new AuditOverState());
context.doWork();
}
} else {
//如果项目经理不同意,就不用交给部门经理了,转向审核结束状态
context.setState(new AuditOverState());
context.doWork();
}
}
}
}
- 部门经理审核状态类
package com.zpc.test.statepattern;
import java.util.Scanner;
public class DepManagerState implements LeaveRequestState {
@Override
public void doWork(StateMachine context) {
//先提取业务对象
LeaveRequestModel businessObj = (LeaveRequestModel) context.getBusinessObj();
System.out.println("部门经理审核中。。。");
//模拟用户界面,从控制台读取数据
System.out.println(businessObj.getUser() + "申请从" + businessObj.getDateBegin() + "开始请假" + businessObj.getLeaveDays() + "天,请部门经理审核(1同意,2不同意):");
Scanner scanner = new Scanner(System.in);
if (scanner.hasNext()) {
int a = scanner.nextInt();
String res = "不同意";
if (a == 1) {
res = "同意";
}
businessObj.setResult("部门经理审核结果:" + res);
//部门经理审核后,转向审核结束状态
context.setState(new AuditOverState());
context.doWork();
}
}
}
- 审核结束状态类
package com.zpc.test.statepattern;
public class AuditOverState implements LeaveRequestState {
@Override
public void doWork(StateMachine context) {
LeaveRequestModel businessObj = (LeaveRequestModel) context.getBusinessObj();
System.out.println(businessObj.getUser()+",请假流程结束,结果是:"+businessObj.getResult());
}
}
- 运行测试
package com.zpc.test.statepattern;
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
//创建业务对象,设置数据
LeaveRequestModel model=new LeaveRequestModel();
model.setUser("鸟鹏");
model.setDateBegin("20180930");
//model.setLeaveDays(1);
model.setLeaveDays(4);
LeaveRequestContext context=new LeaveRequestContext();
context.setBusinessObj(model);
//配置上下文的初始状态,以后就随流程而动态变化(状态驱动)
context.setState(new ProjectManagerState());
context.doWork();
}
}
手动在控制台输入1(同意),2(不同意)试试看!
实际开发中可以使用数据库存储工作流状态信息和审核结果,每次运行的时候从数据库获取这些值。
