设计模式之责任链模式

介绍

​张三带着她的女朋友去吃海底捞,刚到门口,站在店门口的服务员A打开门道一句欢迎光临,服务员B带着两位找到合适的位置坐下,服务员C拿着平板过来给女朋友点单,毛肚、鸭肠、牛肚、鸭血、脑花、宽粉、肥牛肥羊、虾滑,哎呦这妹子和我能吃到一块儿,过了一会,服务员D推着小车把菜品送过来为两位客人烫菜并亲自给两位调好了小料,一个小时后,两人烫完了火锅,张三开始结账买单,在离开海底捞的时候女朋友又去店门口服务员E那里免费做了个美甲。嗨呦真不错。

​从这顿海底捞中,负责开门的服务员A,领路的服务员B,提供点单的服务员C,点单的女朋友,送菜的服务员D,买单的张三,以及最后负责美甲的服务员E,不同的人负责着不同的事,每个人各司其职。

到这里就引入了我们今天的主题:责任链模式。

责任链模式是11个行为型设计模式中的一个,从字面上可以这样理解:首先有一个链chain,这条链是由多个处理当前请求的处理器有先后顺序地组成的,这条链上的每一个处理器都有责任处理接收到的请求。即由多个不同的责任方组成链表的形式按顺序处理接收到的请求。

在责任链方式中,每一个责任方都是请求的接收者,一个责任方处理完成后将请求传递给下一个责任方,这样就有效地将请求的发起方和处理方进行解耦。

百度百科是这样解释的:

​ 责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

优点:

  • 降低耦合度。它将请求的发送者和接收者解耦。

  • 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。

  • 增加新的请求处理类很方便。

缺点:

  • 由于是多个责任方组成的链,所以存在循环调用的可能性

接下来看看责任链模式中有哪些元素组成

组成

  • 抽象责任方:将各个不同的责任方的功能抽象起来,提供统一的公共api
  • 具体责任方:抽象责任方的具体实现,每一个责任方有着不同的处理逻辑
  • Chain:由每一个责任方组成的链。

两种实现

  • 实现一:在链Chain中,当一个责任方无法处理当前请求时,将该请求传递给下一个责任方,如此往复,直到找到一个可以处理当前请求的责任方并将请求交给此责任方处理为止。即该链Chain中只能有一个责任方处理请求。

    如:在spring中,想必每一个人都写过自己的拦截器组件HandlerInterceptor,我们的拦截器和spring内部的拦截器就一同形成一个拦截器链,每一个拦截器负责不同的功能,每一个拦截器的prehandle()方法如果返回true,则将请求交给下一个拦截器,直到有个拦截器的prehandle()方法如果返回false,后面的责任方就不再处理请求了。

  • 实现二:在链Chain中,每一个责任方都有机会处理当前请求,一个责任方处理完成后,将请求交给下一个责任方处理。

实现一

在日常生活中有许多事情需要向领导提出申请,而领导审核通过后可能还有更大的领导进行审批。比如你女朋友喊你去嗦粉,你需要向公司领导提交一份申请,首先由小组组长审核,审核通过后由项目领导审核,接下来是部门领导,直到大BOSS。

在本例中,我们通过使用责任链模式模拟费用报销的报销流程。当我们提交一份报销申请时,小组组长进行审核,审核通过后,交由项目组长审核,接下来是部门领导,最后是CEO,在审核过程中,无论哪个审核人审核拒绝,都会导致审核流程的结束。当CEO审核通过后,表示该申请通过审核。

  • 抽象责任方

    所有领导都有一个共同的责任,就是对申请进行审核

public interface Leader {
    /**
     * 对金额进行审核
     * @param amount 金额
     * @return true-审核通过,false-审核不通过
     */
    Boolean approve(BigDecimal amount);
}
  • 具体责任方

    每一个领导的审核标准可能不同,小组领导和CEO在审核一个申请时都有各自的考虑,这是他们不同的地方,为了方面演示,我们定义不同的领导对金额数字有不同的怪癖,比如:小组组长无法忍受金额为100元的申请,必定会驳回100元的申请,其他金额一律通过审核,类似的,项目组长无法忍受200元,部门领导300元,CEO无法忍受400元。

// 小组组长
public class TeamLeader implements Leader {

    private final Leader leader;

    public TeamLeader() {
        // 小组组长下一个审核者为项目领导
        this.leader = new ProjectLeader();
    }

    /**
     * 对金额进行审核
     * @param amount 金额
     * @return true-审核通过,false-审核不通过
     */
    @Override
    public Boolean approve(BigDecimal amount) {
        if (amount.compareTo(new BigDecimal("100")) == 0) {
            log.error("团队小组长审核不通过,原因:此人无法忍受100元");
            return false;
        } else {
            log.info("团队小组长审核通过");
            return leader.approve(amount);
        }
    }
}

// 项目领导
public class ProjectLeader implements Leader {

    private final Leader leader;

    public ProjectLeader() {
        // 项目领导下一位审核者为部门领导
        this.leader = new DepartmentLeader();
    }

    /**
     * 对金额进行审核
     * @param amount 金额
     * @return true-审核通过,false-审核不通过
     */
    @Override
    public Boolean approve(BigDecimal amount) {
        if (amount.compareTo(new BigDecimal("200")) == 0) {
            log.error("项目经理审核不通过,原因:此人无法忍受200元");
            return false;
        } else {
            log.info("项目经理审核通过");
            return leader.approve(amount);
        }
    }
}

// 部门领导
public class DepartmentLeader implements Leader {


    private final Leader leader;

    public DepartmentLeader() {
        // 部门领导下一位审核者为CEO
        this.leader = new CEO();
    }

    /**
     * 对金额进行审核
     * @param amount 金额
     * @return true-审核通过,false-审核不通过
     */
    @Override
    public Boolean approve(BigDecimal amount) {
        if (amount.compareTo(new BigDecimal("300")) == 0) {
            log.error("部门老大审核不通过,原因:此人无法忍受300元");
            return false;
        } else {
            log.info("部门老大审核通过");
            return leader.approve(amount);
        }
    }
}

// CEO
public class CEO implements Leader {

    /**
     * 对金额进行审核
     * @param amount 金额
     * @return true-审核通过,false-审核不通过
     */
    @Override
    public Boolean approve(BigDecimal amount) {
        if (amount.compareTo(new BigDecimal("400")) == 0) {
            log.error("CEO审核不通过,原因:此人无法忍受400元");
            return false;
        } else {
            log.info("CEO审核通过");
            return true;
        }
    }
}
  • 责任链Chain

从上面的四个具体责任方的实现可以看出来一个关系链

在这里插入图片描述

其实我们可以把申请直接提交给小组组长,小组组长审核通过后沿着这条审核链传递申请,但这样做就无疑把申请的发起人和审批人耦合在一起了。

于是将上述链表添加一个责任链的引用。

public class ApproveChain {

    private Leader leader;

    public ApproveChain() {
        // 该责任链的第一个审核人为小组领导
        this.leader = new TeamLeader();
    }

    public Boolean handle(BigDecimal amount) {
        return leader.approve(amount);
    }
}

这样一来,责任链的结构如下所示

在这里插入图片描述

发起人其实直接把申请丢给审核流程即可,审核流程中都有哪些审核人,审核人的顺序是怎样的,发起人无需关心

示例:

// 小组组长审核驳回
public static void main(String[] args) {

    ApproveChain chain = new ApproveChain();

    BigDecimal amount = new BigDecimal("100");

    Boolean approveResult = chain.handle(amount);

    if (!approveResult) {
        log.error("结果:审核失败");
    } else {
        log.error("结果:审核通过");
    }
}

输出:

在这里插入图片描述

// 项目领导审核驳回
public static void main(String[] args) {

    ApproveChain chain = new ApproveChain();

    BigDecimal amount = new BigDecimal("200");

    Boolean approveResult = chain.handle(amount);

    if (!approveResult) {
        log.error("结果:审核失败");
    } else {
        log.error("结果:审核通过");
    }
}

输出:
在这里插入图片描述

// 部门领导审核驳回
public static void main(String[] args) {

    ApproveChain chain = new ApproveChain();

    BigDecimal amount = new BigDecimal("300");

    Boolean approveResult = chain.handle(amount);

    if (!approveResult) {
        log.error("结果:审核失败");
    } else {
        log.error("结果:审核通过");
    }
}

输出:

在这里插入图片描述

// CEO审核驳回
public static void main(String[] args) {

    ApproveChain chain = new ApproveChain();

    BigDecimal amount = new BigDecimal("400");

    Boolean approveResult = chain.handle(amount);

    if (!approveResult) {
        log.error("结果:审核失败");
    } else {
        log.error("结果:审核通过");
    }
}

输出:

在这里插入图片描述

实现二

在这种责任链模式的实现中,后续的责任方与前面的责任方没有任何关联,不像上面的审核流程那样,后面领导的审核与前面领导的审核结果有着明显的联系。这种责任链的目的不是为了在适当的责任方中结束链的调用,而是在责任链上每一个责任方都负责做一些事情,比如:

  • 接收参数
  • 日志记录
  • 逻辑处理
  • 异常处理

总结

  • 责任链模式是一种把多个处理器以链的形式串联起来,按顺序处理请求的模式
  • 责任链模式的好处
    • 调用方与逻辑处理方解耦
    • 责任链中顺序可以随意修改,添加责任方也很方便- -
  • 责任链模式的坏处
    • 稍不注意就有可能造成循环调用
  • 责任链尝尝使用于过滤器拦截器等应用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

理想万岁万万岁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值