复盘审批流设计思想

2,506 阅读3分钟

一、简述需求

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);
    }}

四、异步通知

  1. 考虑到 消息通知 的扩展性和可配置性,定义消息通知接口,分别定义 钉钉、邮件等消息通知渠道,根据配置,灵活切换通知途径;

  2. 因为 消息通知 无需实时同步,所以通过AsyncEventBus的方式,异步通知;

五、异步记录操作日志

因为在使用过程中,可能出现各种问题,所以需要记录操作日志,方面日后问题排查。

六、功能下沉为一个平台

  1. 流程定义;
  2. 流程解析;
  3. 后台管理;

链接:juejin.cn/post/692598…