设计模式-行为型模式:责任链模式

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 设计模式-行为型模式:责任链模式

1、简介

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理该请求。在责任链模式中,处理者通过组成一条链,形成一个处理者链,每个处理者都有机会处理请求,直到请求被处理完毕或者没有任何处理者能够处理该请求。

2、组成部分

责任链模式是由多个处理者对象组成的一个链式结构,它包括以下两个组成部分:

  1. 抽象处理者(Handler):定义了一个处理请求的方法,通常是一个抽象类或接口,具体的处理者实现该方法。抽象处理者还可以定义一个指向下一个处理者对象的引用,以形成责任链。
  2. 具体处理者(Concrete Handler):实现了抽象处理者中定义的处理请求的方法,如果能够处理请求,则处理请求,否则将请求传递给下一个处理者对象。

在责任链模式中,每个具体处理者对象都可以根据自己的判断逻辑,选择将请求处理掉,或者传递给下一个处理者对象,这样就形成了一条链式结构,每个请求都会从链的头部开始,一直传递到链的尾部,直到某个处理者对象处理了请求,或者所有的处理者对象都无法处理该请求。由于每个具体处理者对象都只需要处理自己关注的请求类型,所以责任链模式可以实现请求的动态处理,提高代码的灵活性和可扩展性。

3、优缺点

责任链模式是一种常用的设计模式,其主要优点和缺点如下:

优点:

  1. 降低耦合度:责任链模式可以将请求的发送者和接收者解耦,使得请求发送者不需要知道哪个接收者会处理请求。
  2. 灵活性:责任链模式可以动态地组合处理者对象,实现灵活的请求处理过程。
  3. 可扩展性:可以很方便地添加或删除处理者对象,实现责任链的动态调整。
  4. 可维护性:责任链模式可以将复杂的请求处理过程分解为多个简单的处理步骤,并将每个步骤封装在一个处理者对象中,便于维护和扩展。
  5. 提高系统性能:责任链模式可以避免将一个请求发送给所有的接收者,从而提高系统的处理性能。

缺点:

  1. 处理不了循环依赖的问题:如果责任链上的处理者对象之间存在循环依赖,就可能导致死循环或者无法正确处理请求。
  2. 可能导致请求得不到处理:如果责任链上的所有处理者对象都无法处理请求,就会导致请求得不到处理,从而浪费系统资源。
  3. 降低系统的稳定性:如果责任链上的某个处理者对象出现故障或者错误,就可能导致整个系统崩溃。

4、使用场景

责任链模式是一种行为型设计模式,通常在以下场景中使用:

  1. 处理请求的场景:如果有多个对象可以处理同一个请求,但是每个对象可以处理的请求类型不同,或者处理请求的顺序不同,那么可以使用责任链模式。例如,一个网络服务器接收到一个请求后,需要先检查请求是否合法,然后再对请求进行处理,最后将响应发送给客户端。这个过程可以分成多个处理步骤,并将每个步骤封装在一个处理者对象中。
  2. 请求的处理顺序不确定的场景:在某些情况下,请求的处理顺序可能不确定,或者需要在运行时动态地决定请求的处理顺序。此时,可以使用责任链模式。例如,一个采购系统需要根据采购请求的金额和种类来决定是否需要多个部门的审批,这些部门的审批顺序可能不同,可以将每个部门的审批封装在一个处理者对象中,然后根据采购请求的金额和种类,动态地组合这些处理者对象,构成一个处理者链。
  3. 需要动态添加或删除处理者的场景:在某些情况下,需要动态地添加或删除处理者对象,以便扩展处理者链或者优化请求处理过程。这时,可以使用责任链模式。例如,一个电商网站需要根据用户的购买记录、信用评分、账户余额等信息来决定是否给用户发放优惠券。这些信息可以由不同的处理者对象来获取,而这些处理者对象可以根据业务需求动态地添加或删除。
  4. 处理请求的对象不需要知道哪个对象处理该请求的场景:在某些情况下,处理请求的对象不需要知道最终哪个对象会处理该请求,而只需要将请求传递给责任链中的第一个处理者对象即可。例如,一个日志记录系统需要将日志分别记录到本地文件、远程服务器、数据库等不同的存储介质中,但是处理请求的对象只需要将日志记录到责任链中的第一个处理者对象中,就可以自动地将日志记录到多个存储介质中。

5、代码实现

在 Java 中实现责任链模式需要创建一个处理者接口或抽象类来定义处理请求的方法,并创建多个具体处理者类来实现该接口或抽象类。处理者对象通常需要维护一个指向下一个处理者的引用,以便将请求转发给下一个处理者。在客户端中,需要将多个处理者对象按照一定顺序组成一个责任链,然后将请求发送给责任链中的第一个处理者。

下面是一个简单的 Java 代码示例,演示如何使用责任链模式来处理采购请求:

首先,我们需要定义一个采购请求类,用于封装采购请求的信息:

1. public class PurchaseRequest {
2. private String item;    // 采购物品
3. private int amount;     // 采购金额
4. 
5. public PurchaseRequest(String item, int amount) {
6. this.item = item;
7. this.amount = amount;
8.     }
9. 
10. public String getItem() {
11. return item;
12.     }
13. 
14. public int getAmount() {
15. return amount;
16.     }
17. }

接下来,我们需要定义一个处理者接口,用于定义处理请求的方法,并定义一个抽象处理者类,实现该接口,并包含一个指向下一个处理者的引用:

1. public interface PurchaseHandler {
2. void handleRequest(PurchaseRequest request);
3. }
4. 
5. public abstract class AbstractPurchaseHandler implements PurchaseHandler {
6. protected PurchaseHandler nextHandler;
7. 
8. public void setNextHandler(PurchaseHandler nextHandler) {
9. this.nextHandler = nextHandler;
10.     }
11. }

然后,我们需要创建多个具体处理者类,继承抽象处理者类,实现处理请求的方法,并根据业务需求判断是否需要将请求转发给下一个处理者:

1. public class DepartmentHandler extends AbstractPurchaseHandler {
2. public void handleRequest(PurchaseRequest request) {
3. if (request.getAmount() < 1000) {
4.             System.out.println("DepartmentHandler approved the purchase of " + request.getItem());
5.         } else if (nextHandler != null) {
6.             nextHandler.handleRequest(request);
7.         } else {
8.             System.out.println("Sorry, your request for " + request.getItem() + " cannot be approved.");
9.         }
10.     }
11. }
12. 
13. public class ManagerHandler extends AbstractPurchaseHandler {
14. public void handleRequest(PurchaseRequest request) {
15. if (request.getAmount() < 5000) {
16.             System.out.println("ManagerHandler approved the purchase of " + request.getItem());
17.         } else if (nextHandler != null) {
18.             nextHandler.handleRequest(request);
19.         } else {
20.             System.out.println("Sorry, your request for " + request.getItem() + " cannot be approved.");
21.         }
22.     }
23. }
24. 
25. public class CEOHandler extends AbstractPurchaseHandler {
26. public void handleRequest(PurchaseRequest request) {
27. if (request.getAmount() < 10000) {
28.             System.out.println("CEOHandler approved the purchase of " + request.getItem());
29.         } else {
30.             System.out.println("Sorry, your request for " + request.getItem() + " cannot be approved.");
31.         }
32.     }
33. }

最后,在客户端中,我们需要将多个处理者对象按照一定顺序组成一个责任链,并将请求发送给责任链中的第一个处理者:

1. public class Client {
2. public static void main(String[] args) {
3. PurchaseRequest request1 = new PurchaseRequest("Pen", 800);
4. PurchaseRequest request2 = new PurchaseRequest("Phone", 5000);
5. PurchaseRequest request3 = new PurchaseRequest("Laptop", 15000);
6. 
7. DepartmentHandler departmentHandler = new DepartmentHandler();
8. ManagerHandler managerHandler = new ManagerHandler();
9. CEOHandler ceoHandler = new CEOHandler();
10. 
11.     departmentHandler.setNextHandler(managerHandler);
12.     managerHandler.setNextHandler(ceoHandler);
13. 
14.     departmentHandler.handleRequest(request1);
15.     departmentHandler.handleRequest(request2);
16.     departmentHandler.handleRequest(request3);
17.     }
18. }

在上面的客户端代码中,我们首先创建了三个采购请求对象,分别对应于购买笔、手机和笔记本电脑。然后,我们创建了三个具体处理者对象,即部门经理处理者、总经理处理者和CEO处理者。接着,我们将这三个处理者对象按照一定顺序组成一个责任链,即部门经理处理者处理不了的请求将转发给总经理处理者,总经理处理者处理不了的请求将转发给CEO处理者。最后,我们将三个采购请求对象发送给部门经理处理者,观察每个请求的处理结果。

运行上面的代码,我们可以得到如下输出:

       DepartmentHandler approved the purchase of Pen

       ManagerHandler approved the purchase of Phone

       CEOHandler approved the purchase of Laptop

从输出结果可以看出,当采购请求的金额小于 1000 时,部门经理处理者会批准请求;当采购请求的金额介于 1000 和 5000 之间时,总经理处理者会批准请求;当采购请求的金额介于 5000 和 10000 之间时,CEO处理者会批准请求;当采购请求的金额超过 10000 时,所有处理者都无法处理请求。这符合责任链模式的工作原理。

需要注意的是,在实际应用中,责任链模式中的每个处理者都应该具备一定的处理能力和处理权限,不能只是简单地转发请求。否则,责任链模式可能会失去效果,反而增加了系统的复杂性。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
29天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
55 9
|
17天前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
36 0
|
1月前
|
设计模式 监控 算法
Java设计模式梳理:行为型模式(策略,观察者等)
本文详细介绍了Java设计模式中的行为型模式,包括策略模式、观察者模式、责任链模式、模板方法模式和状态模式。通过具体示例代码,深入浅出地讲解了每种模式的应用场景与实现方式。例如,策略模式通过定义一系列算法让客户端在运行时选择所需算法;观察者模式则让多个观察者对象同时监听某一个主题对象,实现松耦合的消息传递机制。此外,还探讨了这些模式与实际开发中的联系,帮助读者更好地理解和应用设计模式,提升代码质量。
Java设计模式梳理:行为型模式(策略,观察者等)
|
28天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
本教程详细讲解了Kotlin语法,适合需要深入了解Kotlin的开发者。对于希望快速上手Kotlin的读者,推荐查阅“简洁”系列教程。本文通过学生会经费申请的例子,介绍了责任链模式及其在Kotlin中的实现,并使用偏函数进行了改进,使代码更加简洁和灵活。
15 0
|
1月前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
37 0
|
1月前
|
设计模式 JavaScript Scala
Kotlin学习笔记 - 改良设计模式 - 责任链模式
Kotlin学习笔记 - 改良设计模式 - 责任链模式
42 0
|
2月前
|
设计模式 缓存 监控
Java设计模式-责任链模式(17)
Java设计模式-责任链模式(17)
|
1月前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
26 0
|
3月前
|
设计模式 算法 Java
【十六】设计模式~~~行为型模式~~~策略模式(Java)
文章详细介绍了策略模式(Strategy Pattern),这是一种对象行为型模式,用于定义一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法独立于使用它的客户而变化,提高了系统的灵活性和可扩展性。通过电影院售票系统中不同类型用户的打折策略案例,展示了策略模式的动机、定义、结构、优点、缺点以及适用场景,并提供了Java代码实现和测试结果。
【十六】设计模式~~~行为型模式~~~策略模式(Java)
|
3月前
|
设计模式 网络协议 Java
【十五】设计模式~~~行为型模式~~~状态模式(Java)
文章详细介绍了状态模式(State Pattern),这是一种对象行为型模式,用于处理对象在其内部状态改变时的行为变化。文中通过案例分析,如银行账户状态管理和屏幕放大镜工具,展示了状态模式的应用场景和设计方法。文章阐述了状态模式的动机、定义、结构、优点、缺点以及适用情况,并提供了Java代码实现和测试结果。状态模式通过将对象的状态和行为封装在独立的状态类中,提高了系统的可扩展性和可维护性。
【十五】设计模式~~~行为型模式~~~状态模式(Java)