前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >漫谈模式之责任链模式

漫谈模式之责任链模式

作者头像
孟君
修改2023-03-22 08:32:08
5170
修改2023-03-22 08:32:08
举报
文章被收录于专栏:孟君的编程札记

今天,我们来分享行为型模式的另外一个成员:责任链模式

责任链模式是一种行为型模式,它允许多个对象来处理请求,从而避免了请求的发送者和接收者之间的直接耦合。

其实,在平时生活或者工作中,我们经常能看到责任链的影子,比如请假和打折的场景。

场景1:请假

某天你想请个假,比如1到3天,直接主管可以审批;3天以上需要部门主管审批;15天以上需要副总裁审批 ... ...

场景2:打折

某天你去买个车,和销售人员讨论折扣的问题。这个时候,可能95折以上销售能拍板;85折需要销售经理拍板;75折需要区域经理拍板 ... ...

这些场景,当某一个人或者节点不能处理的时候,需要抛给下一个节点处理。也就是,每个对象都可以决定是否处理请求或将其传递给下一个对象来处理。这就是我们今天要聊的责任链模式可以做的事情。

责任链模式介绍

意图

责任链的意图是使多个对象都有机会处理请求,从而避免请求的发送者和接收者之前的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

结构

责任链模式的基本结构如下:

Handler

定义一个处理请求的接口。

ConcreteHandler

  • 处理它所负责的请求
  • 可访问它的后继者

责任链模式示例

接下来,我们给一个责任链模式示例模拟买东西打折扣,规则如下:

销售人员能处理9折以上的折扣;如果折扣低于9折向销售经理请示;同理,销售经理能处理8折以上的折扣,如果折扣低于8折,其需要向区域经理请示;区域经理能处理7折以上的折扣。

DiscountHandler (Handler)

折扣处理类,其包含一个折扣处理方法handle, 还有一个后继处理者 successor。

3个ConcreteHandler

定义三个具体的处理者类,分别对应销售人员、销售经理以及区域经理的处理,代码如下:

客户端

模拟不同折扣,测试一下;

输出:

这样,一个获取折扣的责任链模式示例就完成了。

问题来了?

上面的例子很简单,但是责任链的构建不灵活,比如:

需要每个具体处理器去指定后继者(next),如果中间几某一个节点需要增加一个新的,需要手动调整下后继next。有没有一种方式,相对可以灵活一点呢?

接下来,我们写一个Builder工具来完成。

责任链Builder构建工具

在Client端使用如下代码来进行构建。

完整Client端代码如下:

同样运行一下,我们依然可以获取同样的效果。

小结

责任链的多种实现方式

责任链的每一个处理节点其实就是2点。

  • 我是否能处理,能处理则处理掉
  • 不能处理就直接甩给下一个节点来处理

如果将多个处理节点串联起来,一般有如下几种方式:

手动置顶

基于配置文件

比如javax.servlet.Filter,我们可以配置xml来将其串联起来。

基于链表的方式

上述,我们给出了一个结合Builder模式,使用头尾2个节点,把处理器串联起来。

其实,比如处理器返回一个true or false,或者有一个方法展示该节点是否能处理。我们也可以使用基于List或者数组的Chain来完成。接下来,稍微做点调整,为了简单模式,处理器的handle方法返回一个boolean类型。

使用一个List来将各个处理器关联起来。然后,处理器按一个for循环进行处理,只要有一个返回true,就表示已处理,退出循环。如:

客户端Client修改测试一下,同样能拿到结果。

基于注解

也可以写一个注解比如@Chain,比如一个group、name和next属性。含义如下:

  • group - 表示属于哪一个责任链,可以有多个责任链
  • name - 表示处理器名字
  • next - 表示下一个处理器的名字

然后在相关处理器类中标注该注解,可以通过反射对处理器所在package进行扫描,然后将标注@Chain注解的处理器按Group进行分组,并根据name和next串联起来。有兴趣的读者可以自己实现一把。

当然,如果不想使用name或者next,也可以使用一个order属性,指定1,2,3 .... .... 同样也可以按照从小到大完成顺序的串联。

优缺点

优点:

  • 责任链模式能够降低耦合度,使得一个对象无需知道是其他哪一个对象处理其请求。对象仅需知道该请求会被“正确”的处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需要知道链的结构。他们仅需保持一个指向其后继的引用,而不需保持它所有的候选接收者的引用。
  • 当在对象中分派职责时,职责链给你更多的灵活性。你可以通过在运行时刻对该链进行动态的添加或修改来增加或者修改处理一个请求的的那些职责。

缺点

  • 同时也带来了一个问题,既然一个请求没有明确的接收者,那么就不能保证它一定会被处理。该请求可能一直在链的末端都得到不到处理,一个请求也可能因链没有被正确配置而得不到处理。
  • 因为请求需要从链头传递到链尾,如果链过长,可能会影响系统性能。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 责任链模式介绍
  • 责任链模式示例
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档