设计模式-行为型模式-职责链模式

1.职责链模式的定义

避免讲一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求,将接受请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能处理他为止;

1.1 职责链模式的优缺点

优点

  • 降低了对象之间的耦合度
  • 增强了系统的可扩展性,可以根据需要增加新的请求处理类,满足开闭原则;
  • 增强了给对象指派职责的灵活性,当工作流程发生变化时,可以动态的改变链内的成员或者修改他们的次序,也可以动态的新增或删除责任;
  • 职责链简化了对象之间的连接,一个对象只需要保持一个指向其后续的引用,不需要保持其他处理者的引用;
  • 指责分担,每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,符合单一职责原则;

缺点

  • 不能保证每个请求一定被处理,请求可能传递到职责链末端也没有处理的;
  • 对于较长的职责链,请求的处理可能涉及多个处理对象,系统性能受到影响;
  • 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错;

1.2 职责链模式的使用场景

  • 在运行时需要动态使用多个关联对象来处理同一次请求时。比如,请假流程、员工入职流程、编译打包发布上线流程等。

  • 不想让使用者知道具体的处理逻辑时。比如,做权限校验的登录拦截器。

  • 需要动态更换处理对象时。比如,工单处理系统、网关 API 过滤规则系统等。

  • 职责链模式常被用在框架开发中,用来实现框架的过滤器、拦截器功能,让框架的使用者在不修改源码的情况下,添加新的过滤拦截功能.

2.职责链模式的原理

  • 抽象处理类(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后继链接(链上的每个处理类都有一个成员变量来保存下一个处理者的引用);
  • 具体处理类(Concrete Handler):实现抽象处理类的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给他的后继者;
  • 客户端:创建处理链,并向链头的具体处理者提交请求;

3.职责链模式的实现

【实例】

模拟有一个双11期间,业务系统审批的流程,临近双十一公司会有陆续有一些新的需求上线,为了保证线上系统的稳定,我们对上线的审批流畅做了严格的控制.审批的过程会有不同级别的负责人加入进行审批(平常系统上线只需三级负责人审批即可,双十一前后需要二级或一级审核人参与审批),接下来我们就使用职责链模式来设计一下此功能.

【代码】

抽象审核链类

java 复制代码
public abstract class AuthLink {

    protected Logger logger = LoggerFactory.getLogger(AuthLink.class);

    protected SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    protected String levelUserId;      //审核人ID
    protected String levelUserName;   //审核人姓名
    protected AuthLink next;          //持有下一个处理类的引用

    public AuthLink(String levelUserId, String levelUserName) {
        this.levelUserId = levelUserId;
        this.levelUserName = levelUserName;
    }

    //获取下一个处理类
    public AuthLink getNext() {
        return next;
    }

    //责任链中添加处理类
    public AuthLink appendNext(AuthLink next) {
        this.next = next;
        return this;
    }

    //抽象审核方法
    public abstract AuthInfo doAuth(String uId, String orderId, Date authDate);
}

具体处理类

java 复制代码
/*
 * 一级负责人
 */
public class Level1AuthLink extends AuthLink {

    private Date beginDate = f.parse("2020-11-11 00:00:00");
    private Date endDate = f.parse("2020-11-31 23:59:59");

    public Level1AuthLink(String levelUserId, String levelUserName) throws ParseException {
        super(levelUserId, levelUserName);
    }

    @Override
    public AuthInfo doAuth(String uId, String orderId, Date authDate) {
        Date date = AuthService.queryAuthInfo(levelUserId, orderId);
        if (null == date) {
            return new AuthInfo("0001", "单号:", orderId, " 状态:待一级审批负责人 ", levelUserName);
        }
        AuthLink next = super.getNext();
        if (null == next) {
            return new AuthInfo("0000", "单号:", orderId, " 状态:一级审批完成", " 时间:", f.format(date), " 审批人:", levelUserName);
        }
        if (authDate.before(beginDate) || authDate.after(endDate)) {
            return new AuthInfo("0000", "单号:", orderId, " 状态:一级审批完成", " 时间:", f.format(date), " 审批人:", levelUserName);
        }
        return next.doAuth(uId, orderId, authDate);
    }
}

/**
 * 二级负责人
 */
public class Level2AuthLink extends AuthLink {

    private Date beginDate = f.parse("2020-11-11 00:00:00");
    private Date endDate = f.parse("2020-11-31 23:59:59");

    public Level2AuthLink(String levelUserId, String levelUserName) throws ParseException {
        super(levelUserId, levelUserName);
    }

    public AuthInfo doAuth(String uId, String orderId, Date authDate) {
        Date date = AuthService.queryAuthInfo(levelUserId, orderId);
        if (null == date) {
            return new AuthInfo("0001", "单号:", orderId, " 状态:待二级审批负责人 ", levelUserName);
        }
        AuthLink next = super.getNext();
        if (null == next) {
            return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成", " 时间:", f.format(date), " 审批人:", levelUserName);
        }

        if (authDate.before(beginDate) || authDate.after(endDate) ) {
            return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成", " 时间:", f.format(date), " 审批人:", levelUserName);
        }

        return next.doAuth(uId, orderId, authDate);
    }

}

客户端

java 复制代码
public class Client {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_AuthLink() throws ParseException {

        AuthLink authLink = new Level2AuthLink("1000012", "张经理")
                        .appendNext(new Level1AuthLink("1000011", "段总")));

        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date currentDate = f.parse("2020-11-18 23:49:46");

        logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("研发牛马", "1000998004813441", currentDate)));

        // 模拟二级负责人审批
        AuthService.auth("1000012", "1000998004813441");
        logger.info("测试结果:{}", "模拟二级负责人审批,张经理");
        logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("研发牛马", "1000998004813441", currentDate)));

        // 模拟一级负责人审批
        AuthService.auth("1000011", "1000998004813441");
        logger.info("测试结果:{}", "模拟一级负责人审批,段总");
        logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("研发牛马", "1000998004813441", currentDate)));

    }
}
相关推荐
老蒋每日coding13 小时前
AI Agent 设计模式系列(十九)—— 评估和监控模式
人工智能·设计模式
会员果汁14 小时前
23.设计模式-解释器模式
设计模式·解释器模式
「QT(C++)开发工程师」21 小时前
C++设计模式
开发语言·c++·设计模式
茶本无香1 天前
设计模式之七—装饰模式(Decorator Pattern)
java·设计模式·装饰器模式
漂洋过海的鱼儿1 天前
设计模式——EIT构型(三)
java·网络·设计模式
老蒋每日coding2 天前
AI Agent 设计模式系列(十八)—— 安全模式
人工智能·安全·设计模式
老蒋每日coding2 天前
AI Agent 设计模式系列(十六)—— 资源感知优化设计模式
人工智能·设计模式·langchain
老蒋每日coding2 天前
AI Agent 设计模式系列(十七)—— 推理设计模式
人工智能·设计模式
冷崖2 天前
桥模式-结构型
c++·设计模式
连山齐名2 天前
设计模式之一——堵塞队列
设计模式