使用Java责任链模式优雅实现多级审批

1.背景

现需要实现一个休假审批功能,大致流程就是员工发起请假,然后需要经过各级领导审批后方能通过,使用传统的 if else 实现大致应该需要下面这么写:

if(一级审批通过) {
    if(二级审批通过) {
        if(三级审批通过) {
            // ....

        }

    }

}

从功能实现角度来说毫无问题,但如想要做到动态就很麻烦了,比如中间多了一层审批,这种写法处理起来就有点麻烦了。

结合 Java 责任链模式就可以动态解决这个问题!

责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

2.简单实例

2.1 创建抽象类,封装通用方法

/**
 *
 * @author GodSea
 */
public abstract class ChainHandler {

    /**
     * 下一个处理链
     */
    protected ChainHandler nextHandler;

    public void setNext(ChainHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    /**
     * 处理方法
     */
    public abstract void handler();
}

2.2 分别创建不同级别处理类

1.一级审批

/**
 * 一级审批
 * @author GodSea
 */
public class FirstChainHandler extends ChainHandler {

    @Override
    public void handler() {
        if(approval()) {
            System.err.println("一级审批通过");
            if(this.nextHandler != null) {
                System.err.println("进入二级审批");
                this.nextHandler.handler();
            } else {
                System.err.println("审批结束");
            }
        } else {
            System.err.println("一级审批拒绝");
        }
    }

    private boolean approval() {
        // 执行一级审批处理或审批结果查询
        // ................
        return (int) (Math.random() * 5) < 4;
    }
}

2.二级审批

/**
 * 二级审批
 * @author GodSea
 */
public class SecondChainHandler extends ChainHandler {

    @Override
    public void handler() {
        if(approval()) {
            System.err.println("二级审批通过");
            if(this.nextHandler != null) {
                System.err.println("进入三级审批");
                this.nextHandler.handler();
            } else {
                System.err.println("审批结束");
            }
        } else {
            System.err.println("二级审批拒绝");
        }
    }

    private boolean approval() {
        // 执行二级审批处理或审批结果查询
        // ................
        return (int) (Math.random() * 5) < 4;
    }
}

2.3 创建一个实体类,用于封装不同处理类配置

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class ChainEntity {

    private Integer id;

    private String name;

    private String conf;

    private Integer preId;

    private Integer nextId;
}

2.4 创建枚举,枚举不同处理类

public enum ChainEnum {

    /**一级审批*/
    FIRST_APPROVAL(new ChainEntity(1, "一级审批", "com.example.mqtest.links.impl.FirstChainHandler", null, 2)),
    /**二级审批*/
    SECOND_APPROVAL(new ChainEntity(2, "二级审批", "com.example.mqtest.links.impl.SecondChainHandler", 1, null)),
    ;

    ChainEntity gatewayEntity;

    public ChainEntity getGatewayEntity() {
        return gatewayEntity;
    }

    ChainEnum(ChainEntity gatewayEntity) {
        this.gatewayEntity = gatewayEntity;
    }

    /**
     * 根据 ID 获取责任链处理项
     * @param id
     * @return
     */
    public static ChainEntity getChainEntityWithId(int id) {
        for (ChainEnum value : ChainEnum.values()) {
            if(value.getGatewayEntity().getId() == id) {
                return value.getGatewayEntity();
            }
        }
        return null;
    }

    /**
     * 获取责任链第一个处理项
     * @return
     */
    public static ChainEntity getFirstGatewayEntity() {
        for (ChainEnum value : ChainEnum.values()) {
            if(value.getGatewayEntity().getPreId() == null) {
                return value.getGatewayEntity();
            }
        }
        return null;
    }
}

2.5 使用测试

public class Test {

    public static void main(String[] args) {

        // 获取责任链第一个处理项
        ChainEntity firstGatewayEntity = ChainEnum.getFirstGatewayEntity();
        if(firstGatewayEntity == null) {
            return;
        }
        // 加载处理项
        ChainHandler firstChainHandler = loadChainHandler(firstGatewayEntity);
        if(firstChainHandler == null) {
            return;
        }
        ChainEntity chainEntityTemp = firstGatewayEntity;
        ChainHandler chainHandlerTemp = firstChainHandler;
        // 迭代遍历所有handler,以及将它们链接起来
        while (chainEntityTemp.getNextId() != null) {
            ChainEntity chainEntityWithId = ChainEnum.getChainEntityWithId(chainEntityTemp.getNextId());
            ChainHandler chainHandler = loadChainHandler(chainEntityWithId);
            if(chainHandler == null) {
                continue;
            }
            chainHandlerTemp.setNext(chainHandler);
            chainEntityTemp = chainEntityWithId;
            chainHandlerTemp = chainHandler;
        }
        firstChainHandler.handler();
    }

    private static ChainHandler loadChainHandler(ChainEntity firstGatewayEntity) {
        try {
            return (ChainHandler) Class.forName(firstGatewayEntity.getConf()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

2.6 测试截图

1.一级审批直接拒绝

使用Java责任链模式优雅实现多级审批_第1张图片

2.二级审批拒绝

使用Java责任链模式优雅实现多级审批_第2张图片

3.全流程结束

使用Java责任链模式优雅实现多级审批_第3张图片

3.总结

使用责任链解决这类问题代码的可读性和可维护性都很高,后期需要插入审批直接维护枚举类即可,像权限控制、过滤器拦截器这些都是可以用这种方式实现,最后还是要提醒一下:也不要为了使用而使用,结合业务场景选择,如果本身业务就不复杂强行使用这个模式反而适得其反,给自己增加工作量

你可能感兴趣的:(责任链模式,java)