因为 公司之前是准备做一个项目, 项目中涉及了很多业务流程, 然后 公司是准备使用开源的工作流引擎来处理其中的业务流程, 然后 这个HXFlow是我对于工作流的自己的理解, 然后 自己将其实现了一下.., 我们这里只说一下思路

当然 这个也算是在扯淡吧, 有很多开源的相关的东西[activiti 等等], 在实际工作中, 我们差不多是只需要查查资料 使用就行了

GitHub - 970655147/HXFlow

状态机

首先来一张图, 这是一个示例的业务流程图

20/05 HXFlow_ci

首先介绍一下图中的元素

角色[role] : 用户的角色, 各个业务流程之间的跳转是在各个角色之间流动, 流程也是绑定在角色上面的

用户[user] : 绑定在一个/多个流程上的用户

状态[state] : 业务流程中的元素, 在整个状态流转图中扮演"顶点"的角色

动作[action] : action处理业务流程中某个状态向其他状态跃迁

state 和action 可以唯一的确定下一个目标状态, 可以将其抽象的理解为业务业务流转图中的"边"

将其放在我们这里的示例上面

pic, rm 属于角色, zhangsan, zhangsansan属于用户

申请, 审核, 成功, 失败 属于状态, accept, reject, return属于动作

这个 按照我的理解就是一个状态机[图], 各个state为图的顶点, state 和action构成图的边

然后 我们的状态机需要做的事情, 就是 根据当前state 和给定的action获取 目标状态 以及获取一个处理状态跃迁逻辑的handler

这里首先介绍的是这里涉及的三个元素 : State, Action, StateMachine

State
public interface State<T extends State> {

     /**
      * 获取当前状态的id
      *
      * @return StatusType return current state' id
      * @author Jerry.X.He
      * @since 2017/3/15 16:02
      */
     String id();

     /**
      * 创建一个当前State的实例
      *
      * @param id action的id
      * @param extra action的附加信息
      * @return an State instance associate 'id'
      * @author  created at 2017-03-19 18:34
      */
     T create(String id, Object extra);

     /**
      * 获取id对应的state
      *
      * @return StatusType return null if no (id, action) pair, or return corresponding action
      * @author Jerry.X.He
      * @since 2017/3/15 16:02
      */
     T idOf(String id);

     /**
      * 获取当前的状态
      *
      * @return StatusType return current state Object
      * @author Jerry.X.He
      * @since 2017/3/15 16:02
      */
     T status();

     /**
      * 获取当前状态的一些附加的信息
      *
      * @return some extra info bind on current state
      * @author created at 2017-03-19 15:05
      */
     Object extra();

 }Action
public interface Action<T extends Action> {

     /**
      * 获取当前的action的id
      *
      * @return StatusType return current action's id
      * @author Jerry.X.He
      * @since 2017/3/15 16:02
      */
     String id();

     /**
      * 创建一个当前Action的实例
      *
      * @param id action的id
      * @param extra action的附加信息
      * @return an State instance associate 'id'
      * @author  created at 2017-03-19 18:34
      */
     T create(String id, Object extra);

     /**
      * 获取id对应的action
      *
      * @return StatusType return null if no (id, action) pair, or return corresponding action
      * @author Jerry.X.He
      * @since 2017/3/15 16:02
      */
     T idOf(String id);

     /**
      * 获取当前的action
      *
      * @return StatusType return current actionObject
      * @author Jerry.X.He
      * @since 2017/3/15 16:02
      */
     T action();

     /**
      * 获取当前action的一些附加的信息
      *
      * @return some extra info bind on current action
      * @author  created at 2017-03-19 15:05
      */
     Object extra();

 }StateMachine
public interface StateMachine<StateType extends State, ActionType extends Action> {

     /**
      * 获取当前状态机对应的状态的初始状态
      *
      * @return the initial state of current state graph
      * @author  created at 2017-03-19 16:17
      */
     StateType initialState();

     /**
      * 获取当前状态是否还有下一个状态
      *
      * @return true if 'now' could transfer to another state
      * @author  created at 2017-03-19 16:18
      */
     boolean hasNextState(StateType now);

     /**
      * 获取当前状态是否下可以采取的操作
      *
      * @return return based on `now`, what actions can be apply
      * @author  created at 2017-03-22 22:34
      */
     List<ActionType> nextActions(StateType now);

     /**
      * 根据当前的状态 以及采取的动作获取下一个状态
      * 如果没有对应的跃迁, 返回null
      *
      * @param now    当前状态
      * @param action 当前状态采取的action
      * @return StateType return result status while 'now' invoke 'action'
      * @author Jerry.X.He
      * @since 2017/3/15 16:01
      */
     StateType getState(StateType now, ActionType action);

     /**
      * 根据当前的状态 以及采取的动作获取处理当前转换的handler
      * 如果没有对应的跃迁, 返回null
      *
      * @param now    当前状态
      * @param action 当前状态采取的action
      * @return TransferHandler return handler while 'now' invoke 'action'
      * @author Jerry.X.He
      * @since 2017/3/15 16:01
      */
     TransferHandler<StateType, ActionType> getHandler(StateType now, ActionType action);

 }State
State 中核心的东西是id, status, extra, 最初我是想使用status来唯一确定一个状态, 这个思路类似于equals, 可以自己来重写getStatus来判定两个State对象是否是"相同", 但是 后来想了一下万一用户的思路和我不一样呢? 他偏要使用getStatus来做其他的事情呢??, 后来就不打算使用getStatus了, 这个方法估计 之后也会被"废弃", 不过 还是得思量思量, 暂时留在这里吧
然后id存在的意义是使用其他的格式来定义状态机的时候[比如使用json, xml等等来配置流程], 唯一的确定当前状态
extra的存在的意义是存储绑定在当前State上面的额外的其他信息[不可变]
然后 还剩下了两个约定的方法, create, idOf, 两个都主要是将其他格式的数据解析为状态机的时候需要使用的方法 
create 顾名思义就是创建一个State对象[如何实现 用户决定]
idOf 获取id关联的状态, 从状态池中获取id关联的State对象
这里 没有使用Factory, 因为 我个人觉得State对象应该是有限的[枚举], 但是 具体怎么实现, 还是留给用户吧??
Action
然后Action 和State是差不多的, 这里就不多说了
StateMachine
两个核心的业务方法是, getState, getHandler
getState 根据当前状态 和Action 获取目标状态
getHandler 根据当前状态 和Action 获取处理业务的Handler
对于State, Action 我最初的设想是将它们的扩展类定义为枚举, 但是 我这里只能约定接口, 具体的实现我也管不到
对于两个基本的实现StandardState, StandardAction, 因为 需要十分抽象, 因此 我这里不能将其做成枚举, 不然 配置就配不活了
然后上面的StateMachine又导出了一个新的元素 "Handler", 处理业务的接口
TransferHandler
public interface TransferHandler<StateType extends State, ActionType extends Action> {

     /**
      * 处理转换的handler
      *
      * @param context 当前转换涉及的上下文
      * @return return true if handle complete, or else
      * @author Jerry.X.He
      * @since 2017/3/15 16:02
      */
     boolean handle(TransferContext<StateType, ActionType> context) throws Exception;

 }然后上面的TransferHandler又导出了一个TransferContext, 从TransferContext中可以获取上下文的一些信息, 方便于处理业务
TransferContext
public interface TransferContext<StateType extends State, ActionType extends Action> {

     /**
      * 获取当前状态转换关联的状态机
      *
      * @return return current task
      * @author  created at 2017-03-19 15:05
      */
     StateMachine<StateType, ActionType> stateMachine();

     /**
      * 获取当前状态转换的task
      *
      * @return return current task
      * @author  created at 2017-03-19 15:05
      */
     FlowTaskFacade<StateType, ActionType> task();

     /**
      * 获取当前状态转换的源状态
      *
      * @return return current state
      * @author  created at 2017-03-19 15:05
      */
     StateType srcState();

     /**
      * 获取当前状态转换的action
      *
      * @return return current action
      * @author  created at 2017-03-19 15:05
      */
     ActionType action();

     /**
      * 获取当前状态转换的目标状态
      *
      * @return return result state
      * @author  created at 2017-03-19 15:05
      */
     StateType dstState();

     /**
      * 获取当前状态转换的handler
      *
      * @return return current handler
      * @author  created at 2017-03-19 15:05
      */
     TransferHandler<StateType, ActionType> handler();

     /**
      * 获取当前状态转换的一些附加的信息
      *
      * @return  some extra info bind on current context
      * @author  created at 2017-03-19 15:05
      */
     Object extra();

 }

流程容器

好了 上面的单独的状态机相关的部分 差不多就是这样了, 然后 接下来就看我们的核心的东西了吧, flow容器, task容器

首先 依然是一张图

20/05 HXFlow_workflow_02

这里又可以看到几个新的元素 : FlowEngine, Task

FlowEngine 

流程的容器 以及任务的容器, 然后 还维护了任务的状态的切换, 仅仅控制扭转, 实际的业务留给TransferHandler

Task 

一个流程的实例就是一个任务, 任务会受到流程的StateMachine的约束, 从而不断的流转, 直到流转到最终的State[这里的最终的状态 我这里依然没有做约束, 由TransferHandler进行处理, StateMachine.hasNext可以用于检测某个State是否是最终的状态了]

对了 关于FlowEngine中的task容器, 上面 略微抽象了一点, 还可以具体划分为runningTasks, fininshedTasks等等[待扩展]

首先看看Task的约束

 

FlowTask
public interface FlowTask<StateType extends State, ActionType extends Action> {

     /**
      * 获取当前任务的id
      *
      * @return return current task's id
      * @author created at 2017-03-19 15:57
      */
     String id();

     /**
      * 获取当前任务的flow
      *
      * @return return current flow
      * @author  created at 2017-03-19 15:57
      */
     String flow();

     /**
      * 获取当前任务的状态
      *
      * @return return current state
      * @author  created at 2017-03-19 15:58
      */
     StateType now();

     /**
      * 配置当前task的extra信息
      *
      * @return void
      * @author  created at 2017-03-23 0:15
      */
     void extra(Object extra);

     /**
      * 获取当前task上面的extra信息
      *
      * @return return the extra info binding on this task
      * @author  created at 2017-03-23 0:16
      */
     Object extra();

     /**
      * 转换当前task的state
      *
      * @return true if transfer success or else
      * @author created at 2017-03-19 15:58
      */
     boolean transfer(StateType newState);

 }taskId, flowName, now[当前状态]的获取
extra 额外信息的setter, getter
transfer 更新当前task的状态
对于Task的访问, taskId, flowName是不可变的, now由框架进行约束, extra可以用户自己处理
然后 这里就会出现一个问题, FlowTask中约定了transfer方法, 那么 直接拿给用户了, 用户不就能够更新当前状态了吗?? 不行不行 太危险了,, 因此 还是做一个Facade吧, 控制用户的可访问的权利
因此这里FlowTask对应于一个FlowTaskFacade
FlowTaskFacade
public interface FlowTaskFacade<StateType extends State, ActionType extends Action> {
     /**
      * 获取当前任务的id
      *
      * @return return current task's id
      * @author  created at 2017-03-19 15:57
      */
     String id();

     /**
      * 获取当前任务的flow
      *
      * @return return current flow
      * @author  created at 2017-03-19 15:57
      */
     String flow();

     /**
      * 获取当前任务的状态
      *
      * @return return current state
      * @author  created at 2017-03-19 15:58
      */
     StateType now();

     /**
      * 配置当前task的extra信息
      *
      * @return extra info binding on this task
      * @author created at 2017-03-23 0:15
      */
     void extra(Object extra);

     /**
      * 获取当前task上面的extra信息
      *
      * @return return the extra info binding on this task
      * @author  created at 2017-03-23 0:16
      */
     Object extra();

 }然后 框架中保留的是FlowTask, 然后 给用户使用的是FlowTaskFacade
TaskFacade中去掉了一些 不应该给用户的方法, 一定程度上面保证了安全性
FlowEngine
public interface FlowEngine<StateType extends State, ActionType extends Action> {

     /**
      * 获取当前engine, 所有flow的名称
      *
      * @return return all flow
      * @author  created at 2017-03-19 15:50
      */
     Set<String> flows();

     /**
      * 获取当前engine, 所有正在执行的任务的id
      *
      * @return return all running tasks
      * @author  created at 2017-03-22 20:36
      */
     Set<String> runningTasks();

     /**
      * 获取当前engine, 所有已经完成的任务的id
      *
      * @return return all finished tasks
      * @author 
     Set<String> finishedTasks();

     /**
      * 获取给定的流程的状态机
      *
      * @param flow 给定的流程的id
      * @return com.hx.flow.flow.interf.StateMachine<StateType,ActionType> return `StateMachine` corresponding `flow` or else null returned
      * @author created at 2017-03-22 22:38
      */
     StateMachine<StateType, ActionType> getStateMachine(String flow);

     /**
      * 获取taskId对应的task
      *
      * @param taskId           流程实例id
      * @param taskFacadeOthers 创建task需要的其他信息
      * @return null if the pair of (taskId, task) does not exists or else return the corresponding task
      * @author  created at 2017-03-19 16:25
      */
     FlowTaskFacade<StateType, ActionType> getTask(String taskId, Object taskFacadeOthers);

     /**
      * 部署一个流程
      *
      * @param flow         流程id
      * @param stateMachine 流程对应的状态机
      * @return true if deploy success or else
      * @author created at 2017-03-19 15:50
      */
     boolean deploy(String flow, StateMachine<StateType, ActionType> stateMachine);

     /**
      * 部署一个流程
      *
      * @param flow         流程id
      * @param stateMachine 流程对应的状态机
      * @param force        是否强制部署流程
      * @return true if deploy flow success or else
      * @author created at 2017-03-19 15:50
      */
     boolean deploy(String flow, StateMachine<StateType, ActionType> stateMachine, boolean force);

     /**
      * 部署一个流程
      *
      * @param flow                   流程id
      * @param flowGraph              流程定义的数据
      * @param state                  state[用于构造State]
      * @param action                 action[用于构造Action]
      * @param transferHandlerFactory 构造transferHandler的工具
      * @param transferHandlerOthers  构造transferHandler需要的额外参数
      * @return true if deploy success or else
      * @author created at 2017-03-19 15:50
      */
     boolean deploy(String flow, JSONObject flowGraph, StateType state, ActionType action,
                    TransferHandlerFactory<StateType, ActionType> transferHandlerFactory, Object transferHandlerOthers);

     /**
      * 部署一个流程
      *
      * @param flow                   流程id
      * @param flowGraphPath          流程定义的数据的文件的路径
      * @param state                  state[用于构造State]
      * @param action                 action[用于构造Action]
      * @param transferHandlerFactory 创建TransferHandler的Factory
      * @param transferHandlerOthers  创建TransferHandler需要的其他信息
      * @return true if deploy success or else
      * @author created at 2017-03-19 15:50
      */
     boolean deploy(String flow, String flowGraphPath, StateType state, ActionType action,
                    TransferHandlerFactory<StateType, ActionType> transferHandlerFactory, Object transferHandlerOthers);

     /**
      * 启动一个流程实例
      *
      * @param flow       流程id
      * @param extra      创建task的extra信息
      * @param taskOthers 创建task需要的其他信息
      * @return null if flow does not exists, else return the taskId
      * @author  created at 2017-03-19 15:53
      */
     String startFlowInstance(String flow, Object extra, Object taskOthers);

     /**
      * 启动一个流程实例
      *
      * @param flow            流程id
      * @param extra           创建task的extra信息
      * @param taskOthers      创建task需要的其他信息
      * @param flowTaskFactory 创建flowTask的factory
      * @return null if flow does not exists, else return the taskId
      * @author created at 2017-03-19 15:53
      */
     String startFlowInstance(String flow, Object extra, Object taskOthers,
                              FlowTaskFactory<StateType, ActionType> flowTaskFactory);

     /**
      * 向flowEngine中增加一个流程实例
      *
      * @param taskId     任务id
      * @param flow       流程id
      * @param state      任务的初始状态
      * @param extra      创建task的extra信息
      * @param taskOthers 创建task需要的其他信息
      * @return null if flow does not exists, else return the taskId
      * @author  created at 2017-03-19 15:53
      */
     boolean addFlowInstance(String taskId, String flow, StateType state, Object extra, Object taskOthers);

     /**
      * 向flowEngine中增加一个流程实例
      *
      * @param taskId          任务id
      * @param flow            流程id
      * @param state           任务的初始状态
      * @param extra           创建task的extra信息
      * @param taskOthers      创建task需要的其他信息
      * @param flowTaskFactory 创建flowTask的factory
      * @return null if flow does not exists, else return the taskId
      * @author  created at 2017-03-19 15:53
      */
     boolean addFlowInstance(String taskId, String flow, StateType state, Object extra, Object taskOthers,
                             FlowTaskFactory<StateType, ActionType> flowTaskFactory);

     /**
      * 处理实例的状态切换
      *
      * @param taskId                             流程实例的id
      * @param action                             采取的action
      * @param extra                              额外的信息
      * @param taskFacadeAndTransferContextOthers 创建taskFacade, transferContext需要的其他信息
      * @return true if 'complete' success or else[have no task, have no action, etc]
      * @throws Exception throw if any Exception happends
      * @author created at 2017-03-19 15:55
      */
     boolean complete(String taskId, ActionType action, Object extra, Object taskFacadeAndTransferContextOthers) throws Exception;

 }

查询的方法跳过

然后deploy是发布一个流程, 可以是直接构造好的StateMachine, 或者JSONObject[构造StateMachine], 或者一个flowGraph:String[我是作为路径][构造StateMachine]

然后 startFlowInstance, addFlowInstance是用于构造task

complete 用于控制业务

好了, 基本的思路差不多 就是这样了, 接下来我会给出一个使用的Demo

然后 还有一些Factory, FlowTaskFactory, FlowTaskFacadeFactory, TaskIdGenerator, TransferContextFactory, TransferHandlerFactory这里就不给出了, 就是 简单的工厂模式

具体的实现, 仅限于篇幅, 这里也不给出了, 之后将其 分享出来..

还有 如果设计有什么缺陷, 或者有什么更好的想法, 欢迎交流讨论 ..