设计模式-责任链模式

设计模式专栏



模式介绍

责任链模式(Chain of Responsibility, COR)是行为模式之一,该模式构造一系列分别担当不同的职责的类的对象来共同完成一个任务,这些类的对象之间像链条一样紧密相连。

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

模式特点

此模式的优点包括:

  1. 责任的分担:每个类只需要处理自己该处理的工作(不该处理的传递给下一个对象完成),明确各类的责任范围,符合类的最小封装原则。
  2. 可以根据需要自由组合工作流程:如工作流程发生变化,可以通过重新分配对象链便可适应新的工作流程。
  3. 类与类之间可以以松耦合的形式加以组织。

然而,责任链模式也有一些缺点,比如因为处理时以链的形式在对象间传递消息,根据实现方式不同,有可能会影响处理的速度。

应用场景

责任链模式的应用场景包括:

  1. 请求处理链:在一个系统中,可能存在多个处理器,每个处理器负责不同的处理逻辑。通过使用责任链模式,可以将这些处理器连接成一个处理链,每个请求按照处理链的顺序依次经过处理器进行处理,直到找到合适的处理器处理请求或者请求被拒绝。这种模式可以实现请求的动态处理和灵活的扩展,提高系统的可维护性和可扩展性。
  2. 日志记录:在日志记录的场景中,可以使用责任链模式来实现不同级别的日志记录。例如,系统中分为普通日志、警告日志和错误日志三个级别,每个级别对应一个处理器,处理器根据日志级别来决定是否处理该日志,以及如何处理。这样,请求日志的对象只需要将日志传递给处理链的第一个处理器,而无需关心具体的处理过程,大大简化了代码的编写和维护。

此外,责任链模式还适用于多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定。例如,一个服务系统中需要处理多个不同种类的数据同步请求,不同的数据验证规则可以通过拆分成不同的校验规则类(类之间形成链式结构)来实现。这种设计模式可以动态指定一组对象处理请求,或添加新的处理者,使系统更加灵活和可扩展。

责任链模式和命令模式的区别

责任链模式和命令模式是两种不同的设计模式,它们在处理请求和命令的方式上存在明显的区别。

  1. 责任链模式:

责任链模式是一种行为设计模式,它允许你将请求在多个处理者之间传递,直到有一个处理者能够处理它为止。每个处理者都包含对下一个处理者的引用,因此请求可以沿着这个链传递下去,直到找到一个能够处理它的处理者。

在责任链模式中,每个处理者都尝试处理请求,如果当前处理者无法处理该请求,则将请求传递给链中的下一个处理者。如果链中的所有处理者都无法处理该请求,则该请求被拒绝。

责任链模式的主要优点是它可以动态地添加新的处理者,因此可以轻松地扩展系统的功能。此外,由于请求在链中传递,因此可以按照特定的顺序进行处理,这有助于实现复杂的业务逻辑。

  1. 命令模式:

命令模式是一种结构型设计模式,它封装了一个请求作为一个对象,从而让你使用不同的请求把客户端与服务端操作链接起来。

在命令模式中,客户端发送一个命令对象到服务端,服务端通过调用该命令对象的某个方法来执行相应的操作。这个命令对象可以包含任何与请求相关的信息,例如请求的参数、请求的类型等。

命令模式的主要优点是它可以解耦客户端和服务端之间的操作,客户端只需要发送一个命令对象,而不需要关心具体的服务端操作细节。此外,命令模式还可以支持撤销和重做操作,因为每个命令对象都可以被存储起来,并在需要的时候再次执行。

总结:

责任链模式是一种行为设计模式,它允许你将请求在多个处理者之间传递,直到找到一个能够处理它的处理者。而命令模式是一种结构型设计模式,它封装了一个请求作为一个对象,从而让你使用不同的请求把客户端与服务端操作链接起来。这两种设计模式各有特点,选择哪种设计模式取决于具体的业务需求和使用场景。

代码示例

Java实现责任链模式

下面是一个简单的Java实现责任链模式的示例:

java 复制代码
// 抽象处理器类
abstract class Handler {
    protected Handler next;

    public void setNext(Handler next) {
        this.next = next;
    }

    public abstract void handleRequest(int request);
}

// 具体处理器类1
class ConcreteHandler1 extends Handler {
    public void handleRequest(int request) {
        if (request > 0) {
            System.out.println("ConcreteHandler1 handles request: " + request);
        } else if (next != null) {
            next.handleRequest(request);
        }
    }
}

// 具体处理器类2
class ConcreteHandler2 extends Handler {
    public void handleRequest(int request) {
        if (request < 0) {
            System.out.println("ConcreteHandler2 handles request: " + request);
        } else if (next != null) {
            next.handleRequest(request);
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        handler1.setNext(handler2); // 连接责任链

        // 发送请求到责任链的头部进行处理
        handler1.handleRequest(-3); // 传递给ConcreteHandler2处理
        handler1.handleRequest(4); // 传递给ConcreteHandler1处理
    }
}

在这个示例中,我们定义了一个抽象的Handler类,它有一个next属性用于指向下一个处理器对象。然后我们创建了两个具体的处理器类ConcreteHandler1ConcreteHandler2,它们分别实现了handleRequest方法来处理特定的请求。在ConcreteHandler1中,它处理大于0的请求,而在ConcreteHandler2中,它处理小于0的请求。如果请求不满足任何一个处理器的条件,则将请求传递给链中的下一个处理器。最后,我们在客户端代码中创建了两个处理器对象,并将它们连接成一个责任链。然后通过调用责任链的头部来处理请求。在这个示例中,我们发送了两个请求,一个小于0,一个大于0,它们分别被ConcreteHandler2ConcreteHandler1处理。

python实现责任链模式

责任链模式是一种行为设计模式,它允许你将请求在多个处理者之间传递,直到有一个处理者能够处理它为止。下面是一个简单的示例,演示如何使用责任链模式:

python 复制代码
class Handler:
    def handle(self, request):
        pass

class ConcreteHandler1(Handler):
    def handle(self, request):
        if request == "Request1":
            return "ConcreteHandler1 handles Request1"
        else:
            return self.next.handle(request)

class ConcreteHandler2(Handler):
    def __init__(self, next_handler=None):
        self.next = next_handler
    
    def handle(self, request):
        if request == "Request2":
            return "ConcreteHandler2 handles Request2"
        else:
            return self.next.handle(request)

class Client:
    def __init__(self, chain):
        self.chain = chain
    
    def execute_request(self, request):
        return self.chain.handle(request)

# 创建责任链
handler1 = ConcreteHandler1()
handler2 = ConcreteHandler2(handler1)
chain = handler2

# 客户端调用责任链处理请求
print(Client(chain).execute_request("Request1"))  # 输出: ConcreteHandler1 handles Request1
print(Client(chain).execute_request("Request2"))  # 输出: ConcreteHandler2 handles Request2
print(Client(chain).execute_request("Request3"))  # 输出: None,因为没有处理者能够处理这个请求,所以返回None

在这个示例中,我们定义了一个抽象的Handler类,它定义了handle方法但没有实现。然后我们创建了两个具体的处理者ConcreteHandler1ConcreteHandler2,它们分别实现了自己的handle方法来处理特定的请求。在ConcreteHandler2的构造函数中,我们传递了ConcreteHandler1作为下一个处理者。最后,我们创建了一个客户端对象,它接受一个责任链并调用其handle方法来处理请求。在这个示例中,责任链是handler2,它会在ConcreteHandler2ConcreteHandler1之间传递请求,直到找到一个能够处理请求的处理者。如果没有处理者能够处理请求,则返回None。

责任链模式在spring中的应用

在Spring框架中,责任链模式主要体现在拦截器(Interceptor)和处理器(Handler)的处理过程中。

Spring MVC框架中的DispatcherServlet是前端控制器,它会接收所有的HTTP请求,然后根据请求的信息(如URL、HTTP方法、请求头等)决定将这些请求交给哪个处理器(Handler)处理。处理器可能是一个Controller,也可能是一个其他的处理器,如HandlerMethodHandlerExecutionChain等。这些处理器就形成了一个处理请求的链式结构,每个处理器都有机会处理请求,如果某个处理器处理不了,就会将请求传递给链中的下一个处理器,这就是责任链模式的一种体现。

除了处理器之外,Spring MVC还提供了拦截器(Interceptor)机制。拦截器可以在请求被处理之前或之后执行一些操作,比如权限验证、日志记录等。拦截器也是链式调用的,每个拦截器都有机会处理请求,如果某个拦截器处理不了,就会将请求传递给链中的下一个拦截器,这也是责任链模式的一种体现。

在Spring Security中,也大量使用了责任链模式。例如,身份验证过滤器链(Security Filter Chain)就是一个典型的责任链模式应用。这个链中包含了多个身份验证过滤器(Security Filter),每个过滤器都会尝试对请求进行身份验证,如果某个过滤器无法处理该请求,就会将请求传递给链中的下一个过滤器。这种设计使得身份验证的过程非常灵活,可以轻松地添加或删除身份验证的策略。

总的来说,Spring框架中的很多设计都采用了责任链模式,这种模式使得系统具有很好的可扩展性和灵活性,可以方便地添加新的处理逻辑或修改现有的处理逻辑。

相关推荐
BillKu17 分钟前
Java + Spring Boot + Mybatis 插入数据后,获取自增 id 的方法
java·tomcat·mybatis
全栈凯哥18 分钟前
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
java·算法·leetcode·链表
chxii19 分钟前
12.7Swing控件6 JList
java
全栈凯哥20 分钟前
Java详解LeetCode 热题 100(27):LeetCode 21. 合并两个有序链表(Merge Two Sorted Lists)详解
java·算法·leetcode·链表
YuTaoShao21 分钟前
Java八股文——集合「List篇」
java·开发语言·list
PypYCCcccCc26 分钟前
支付系统架构图
java·网络·金融·系统架构
华科云商xiao徐1 小时前
Java HttpClient实现简单网络爬虫
java·爬虫
扎瓦1 小时前
ThreadLocal 线程变量
java·后端
BillKu1 小时前
Java后端检查空条件查询
java·开发语言
jackson凌1 小时前
【Java学习笔记】String类(重点)
java·笔记·学习