1、简介
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理该请求。在责任链模式中,处理者通过组成一条链,形成一个处理者链,每个处理者都有机会处理请求,直到请求被处理完毕或者没有任何处理者能够处理该请求。
2、组成部分
责任链模式是由多个处理者对象组成的一个链式结构,它包括以下两个组成部分:
- 抽象处理者(Handler):定义了一个处理请求的方法,通常是一个抽象类或接口,具体的处理者实现该方法。抽象处理者还可以定义一个指向下一个处理者对象的引用,以形成责任链。
- 具体处理者(Concrete Handler):实现了抽象处理者中定义的处理请求的方法,如果能够处理请求,则处理请求,否则将请求传递给下一个处理者对象。
在责任链模式中,每个具体处理者对象都可以根据自己的判断逻辑,选择将请求处理掉,或者传递给下一个处理者对象,这样就形成了一条链式结构,每个请求都会从链的头部开始,一直传递到链的尾部,直到某个处理者对象处理了请求,或者所有的处理者对象都无法处理该请求。由于每个具体处理者对象都只需要处理自己关注的请求类型,所以责任链模式可以实现请求的动态处理,提高代码的灵活性和可扩展性。
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 时,所有处理者都无法处理请求。这符合责任链模式的工作原理。
需要注意的是,在实际应用中,责任链模式中的每个处理者都应该具备一定的处理能力和处理权限,不能只是简单地转发请求。否则,责任链模式可能会失去效果,反而增加了系统的复杂性。