一、简述需求
1、审批流,涉及三个阶段,每个阶段分别有不同的角色审批;
2、存在一个流程管理员角色、可以跳过、退回、编辑其他成员的结论等功能;
3、存在并行审批的场景;
4、消息通知,用户审批;
二、抽象模型
1、抽取主逻辑
因为存在跳过、退回、流程管理员编辑其他成员的操作,会增加很多特殊场景,如果优先将所有的特殊场景先列举出来,会发现到造成思维混乱,影响代码设计。所以 我先抛开各种个数场景,来思考一个普通的审批流是什么样的。下面就是简化版的审批流。
基于上面的流程图,处理出了第一个模板方法
public interface processHandle {
void doAction(Object o1);
}
public interface ApprovalProcessHandle extends processHandle { default void doAction(Object o1){
Boolean processFinished = isFinished(o1);
if (processFinished) {
doFinish(o1);
noticeMember(o1);
} else {
Boolean jumpNextProcess = jumpNextProcess(o1);
if (jumpNextProcess) {
String nextProcess = getNextProcess(o1);
doJumpNextProcess(o1, nextProcess);
noticeMember(o1);
} else {
doCurProcess(o1);
}
}
}
void doCurProcess(Object o1);
void doJumpNextProcess(Object o1, String nextProcess);
String getNextProcess(Object o1);
Boolean jumpNextProcess(Object o1);
void noticeMember(Object o1);
void doFinish(Object o1);
Boolean isFinished(Object o1);
}
接下来我们写各个阶段的具体逻辑,只需要继承此模板处理器,重写具体实现即可;
2、添加特殊处理场景
1)跳过评审;
2)退回阶段二,重新评审;
分别对应下图中路线部分;
因为处理逻辑和上面的模板不一致,所以我们需要 继承 processHandle,重写doAction方法。 将特殊场景单独处理。
3、继续增加特殊场景的处理
1)阶段三的角色(pmo) 有编辑阶段二的评审结论的权限;
其流程如下图红色部分所示:
因为是特殊场景,所以也需要增加特殊类的处理,同2的实现一致。同时 pmo 编辑阶段二的结论 和 阶段二的角色 提交结论的部分操作是一致的,鉴于此,我们可以使用代理模式,将相同部分的操作委托给 阶段二的成员操作
4、总结:
通过上方1、2、3的分析,一面使用了 模板模式和代理模式,另外更重要的是,分析复杂问题的方法。
- 1、跳出具体的业务场景;
- 2、高纬度的思考问题业务模型;
- 3、为特殊场景预留扩展;
- 4、梳理特殊场景
这种方法便于我们快速理清思路,找出解决方案。
三、整合各种具体实现
整合的过程可以通过两种方式实现:
- 1、职责链模式
- 2、策略模式
职责链模式
每个 processHandle 中需要增加方法 support(),用来确定是否是当前 处理器处理;
优点:将判断逻辑分散在各个 processHandle 里面,代码逻辑清晰;
缺点:可读性差,需要去各个类中看具体逻辑;
策略模式
在初始化的时候,将各个 processHandle 放在一个map中,阶段+操作+角色 作为key,具体的 processHandle 作为value,可以方便的获取到 对应的 processHandle;
优点:代码可读性增强;
缺点:如果策略较复杂,会增加代码的维护成本;
鉴于当前的逻辑并复杂,为了增加可读性,选择策略模式
public class ProcessManager {
Map<String, ProcessHandle> map = new hashMap<>();
@init
public void init(){
map.put("阶段+操作+角色", AprocessHandle);
map.put("阶段+操作+角色", BprocessHandle);
}
public void handle(Object o){
ProcessHandle handle = map.get(o);
handle.doAction(0);
}}
四、异步通知
-
考虑到 消息通知 的扩展性和可配置性,定义消息通知接口,分别定义 钉钉、邮件等消息通知渠道,根据配置,灵活切换通知途径;
-
因为 消息通知 无需实时同步,所以通过AsyncEventBus的方式,异步通知;
五、异步记录操作日志
因为在使用过程中,可能出现各种问题,所以需要记录操作日志,方面日后问题排查。
六、功能下沉为一个平台
- 流程定义;
- 流程解析;
- 后台管理;