21、Python设计模式:责任链模式

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。这种模式建议让请求的发送者和接收者形成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

哲学思想:

责任链模式的哲学思想是“不要把所有的鸡蛋放在一个篮子里”。这种模式的核心思想是将请求发送者和请求处理者解耦,从而使多个对象都有机会处理请求。这种解耦能够提高系统的灵活性和可扩展性。

简介:

责任链模式是由多个对象组成的一条链。当一个请求发送者发送一个请求时,这个请求会依次经过链中的每一个对象,直到有一个对象处理它为止。每个对象都有处理请求的机会,如果它不能处理请求,就会将请求传递给下一个对象。这种模式的核心是责任链,它将请求和处理请求的对象链接起来,形成一条链。

优点:

1、 解耦性:责任链模式可以将请求发送者和请求处理者解耦,从而使多个对象都有机会处理请求这种解耦能够提高系统的灵活性和可扩展性;
2、 灵活性:责任链模式可以根据需要动态地组织链,并且可以在链中添加或删除处理者这种灵活性可以使系统更加适应变化;
3、 可扩展性:责任链模式可以通过添加或删除处理者来扩展系统的功能,从而实现系统的可扩展性;
4、 简化对象:责任链模式可以将多个对象组合成一个处理链,从而简化对象的结构这种简化能够提高系统的性能和可维护性;

缺点:

1、 处理时间:由于请求经过多个对象处理,所以处理时间可能会比较长这种长时间的处理可能会影响系统的性能;
2、 难以调试:由于请求经过多个对象处理,所以当出现问题时,很难确定是哪个对象出现了问题这种难以调试可能会影响系统的可维护性;
3、 可能会造成循环调用:由于每个对象都有处理请求的机会,所以如果链中的对象没有正确地组织,可能会出现循环调用,从而导致系统的死循环;

实际应用场景:

1、 请求处理:在应用程序中,可能需要将请求按照特定的顺序传递给多个处理程序责任链模式可以使得这些请求能够被有效的处理;
2、 错误处理:在程序中,可能会发生多种类型的错误责任链模式可以将这些错误按照一定的优先级进行处理,确保每个错误都能够被正确的处理;
3、 身份验证:在许多应用程序中,需要对用户进行身份验证责任链模式可以将身份验证请求传递给多个身份验证程序,以确保请求被正确的处理;
4、 安全检查:在应用程序中,需要对用户的请求进行安全检查责任链模式可以将安全检查请求传递给多个安全检查程序,以确保请求被正确的处理;
5、 日志记录:在应用程序中,需要对操作进行日志记录责任链模式可以将日志记录请求传递给多个日志记录程序,以确保请求被正确的处理;

python代码实现:

class Handler:
    def __init__(self, successor=None):
        self._successor = successor

    def handle_request(self, request):
        handled = self._handle(request)
        if not handled:
            self._successor.handle_request(request)

    def _handle(self, request):
        raise NotImplementedError('Must provide implementation in subclass.')

class ConcreteHandler1(Handler):
    def _handle(self, request):
        if 0 < request <= 10:
            print(f'Request {request} handled in handler 1')
            return True

class ConcreteHandler2(Handler):
    def _handle(self, request):
        if 10 < request <= 20:
            print(f'Request {request} handled in handler 2')
            return True

class ConcreteHandler3(Handler):
    def _handle(self, request):
        if 20 < request <= 30:
            print(f'Request {request} handled in handler 3')
            return True

class DefaultHandler(Handler):
    def _handle(self, request):
        print(f'End of chain, no handler for {request}')
        return True

class Client:
    def __init__(self):
        self.handler = ConcreteHandler1(ConcreteHandler2(ConcreteHandler3(DefaultHandler())))

    def delegate(self, requests):
        for request in requests:
            self.handler.handle_request(request)

client = Client()
requests = [2, 5, 14, 22, 18, 3, 35, 27, 20]
client.delegate(requests)

上述代码中,我们定义了一个 Handler 基类,所有具体的处理程序类都应该继承自该类。在基类中,我们定义了一个 handle_request 方法来处理传入的请求。如果当前处理程序可以处理请求,则处理它,否则将请求传递给下一个处理程序。在具体的处理程序子类中,我们重写了 _handle 方法,根据请求的值来确定是否可以处理它。

我们还定义了一个 DefaultHandler 类,它是一个具体的处理程序类,它将处理链的末尾标志为默认处理程序。最后,我们定义了一个 Client 类,它包含一个具体的处理程序对象,可以委托给该对象来处理传入的请求。

我们可以创建一个客户端对象,并传递一组请求来测试该代码。在上述示例中,我们传递了一组请求 [2, 5, 14, 22, 18, 3, 35, 27, 20],并使用 delegate 方法将这些请求委托给处理程序。运行代码后,输出结果如下:

Request 2 handled in handler 1
Request 5 handled in handler 1
Request 14 handled in handler 2
Request 22 handled in handler 3
Request 18 handled in handler 2
Request 3 handled in handler 1
End of chain, no handler for 35
Request 27 handled in handler 3
Request 20 handled in handler 2

代码解释:

在以上代码中,Handler 是抽象处理器,定义了处理请求的基本行为和指向下一个处理器的指针。ConcreteHandler1、ConcreteHandler2 和 ConcreteHandler3 是具体处理器,实现了自己的处理逻辑,并根据自己的条件来决定是否处理该请求。DefaultHandler 是默认处理器,用于处理最后一个处理器无法处理的请求。

Client 是客户端,创建了一个处理器链,并将一系列请求委派给处理器链。

具体来说,以上代码的执行流程如下:

1、 Client创建了一个处理器链:ConcreteHandler1(ConcreteHandler2(ConcreteHandler3(DefaultHandler())));
2、 Client将一系列请求[2,5,14,22,18,3,35,27,20]委派给处理器链;
3、 处理器链开始处理请求首先,ConcreteHandler1尝试处理请求2,但由于该请求不在它的处理范围内,它将请求传递给下一个处理器ConcreteHandler2;
4、 ConcreteHandler2尝试处理请求2,但仍然无法处理,于是将请求传递给下一个处理器ConcreteHandler3;
5、 ConcreteHandler3尝试处理请求2,同样无法处理,于是将请求传递给下一个处理器DefaultHandler;
6、 DefaultHandler处理请求2,并输出日志:"Endofchain,nohandlerfor2";
7、 处理器链继续处理请求ConcreteHandler1尝试处理请求5,成功处理,并输出日志:"Request5handledinhandler1";
8、 ConcreteHandler1继续处理请求14,但由于该请求不在它的处理范围内,它将请求传递给下一个处理器ConcreteHandler2;
9、 ConcreteHandler2成功处理请求14,并输出日志:"Request14handledinhandler2";
10、 ConcreteHandler2继续处理请求22,但由于该请求不在它的处理范围内,它将请求传递给下一个处理器ConcreteHandler3;
11、 ConcreteHandler3成功处理请求22,并输出日志:"Request22handledinhandler3";
12、 ConcreteHandler3继续处理请求18,但由于该请求不在它的处理范围内,它将请求传递给下一个处理器DefaultHandler;
13、 DefaultHandler成功处理请求18,并输出日志:"Endofchain,nohandlerfor18";

以此类推,即可得到最后结果。

ConcreteHandler1(ConcreteHandler2(ConcreteHandler3(DefaultHandler())))

本句代码解释:

具体来说,它使用了装饰器模式(Decorator Pattern)来实现责任链(Chain of Responsibility)模式。

在责任链模式中,每个处理器(Handler)都可以处理一个请求,如果它不能处理这个请求,就把请求传递给下一个处理器,直到有一个处理器能够处理为止。在这个代码片段中,ConcreteHandler1、ConcreteHandler2、ConcreteHandler3、DefaultHandler 都是处理器,它们都继承自同一个 Handler 父类,并且按照一定的顺序组合在一起,形成了一个责任链。

具体来说,这个代码片段的意思是:

1、 DefaultHandler是最底层的处理器,也就是整个责任链的终点如果所有的处理器都不能处理请求,那么就会由DefaultHandler来处理请求;
2、 ConcreteHandler3继承自Handler,并重写了处理请求的方法如果ConcreteHandler3不能处理请求,那么就会将请求传递给它的下一个处理器;
3、 ConcreteHandler2继承自ConcreteHandler3,并重写了处理请求的方法如果ConcreteHandler2不能处理请求,那么就会将请求传递给它的下一个处理器,也就是ConcreteHandler3;
4、 ConcreteHandler1继承自ConcreteHandler2,并重写了处理请求的方法如果ConcreteHandler1不能处理请求,那么就会将请求传递给它的下一个处理器,也就是ConcreteHandler2;

因此,当一个请求到达 ConcreteHandler1 时,它会首先尝试由 ConcreteHandler1 来处理,如果不能处理,则会传递给 ConcreteHandler2,然后是 ConcreteHandler3,最后是 DefaultHandler。

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: