【python设计模式】22、责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。这种模式建议让请求的发送者和接收者形成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
哲学思想:
责任链模式的哲学思想是“不要把所有的鸡蛋放在一个篮子里”。这种模式的核心思想是将请求发送者和请求处理者解耦,从而使多个对象都有机会处理请求。这种解耦能够提高系统的灵活性和可扩展性。
简介:
责任链模式是由多个对象组成的一条链。当一个请求发送者发送一个请求时,这个请求会依次经过链中的每一个对象,直到有一个对象处理它为止。每个对象都有处理请求的机会,如果它不能处理请求,就会将请求传递给下一个对象。这种模式的核心是责任链,它将请求和处理请求的对象链接起来,形成一条链。
优点:
-
解耦性:责任链模式可以将请求发送者和请求处理者解耦,从而使多个对象都有机会处理请求。这种解耦能够提高系统的灵活性和可扩展性。
-
灵活性:责任链模式可以根据需要动态地组织链,并且可以在链中添加或删除处理者。这种灵活性可以使系统更加适应变化。
-
可扩展性:责任链模式可以通过添加或删除处理者来扩展系统的功能,从而实现系统的可扩展性。
-
简化对象:责任链模式可以将多个对象组合成一个处理链,从而简化对象的结构。这种简化能够提高系统的性能和可维护性。
缺点:
-
处理时间:由于请求经过多个对象处理,所以处理时间可能会比较长。这种长时间的处理可能会影响系统的性能。
-
难以调试:由于请求经过多个对象处理,所以当出现问题时,很难确定是哪个对象出现了问题。这种难以调试可能会影响系统的可维护性。
-
可能会造成循环调用:由于每个对象都有处理请求的机会,所以如果链中的对象没有正确地组织,可能会出现循环调用,从而导致系统的死循环。
实际应用场景:
-
请求处理:在应用程序中,可能需要将请求按照特定的顺序传递给多个处理程序。责任链模式可以使得这些请求能够被有效的处理。
-
错误处理:在程序中,可能会发生多种类型的错误。责任链模式可以将这些错误按照一定的优先级进行处理,确保每个错误都能够被正确的处理。
-
身份验证:在许多应用程序中,需要对用户进行身份验证。责任链模式可以将身份验证请求传递给多个身份验证程序,以确保请求被正确的处理。
-
安全检查:在应用程序中,需要对用户的请求进行安全检查。责任链模式可以将安全检查请求传递给多个安全检查程序,以确保请求被正确的处理。
-
日志记录:在应用程序中,需要对操作进行日志记录。责任链模式可以将日志记录请求传递给多个日志记录程序,以确保请求被正确的处理。
python代码实现:
class Handler:def __init__(self, successor=None):self._successor = successordef 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 Trueclass ConcreteHandler2(Handler):def _handle(self, request):if 10 < request <= 20:print(f'Request {request} handled in handler 2')return Trueclass ConcreteHandler3(Handler):def _handle(self, request):if 20 < request <= 30:print(f'Request {request} handled in handler 3')return Trueclass DefaultHandler(Handler):def _handle(self, request):print(f'End of chain, no handler for {request}')return Trueclass 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 是客户端,创建了一个处理器链,并将一系列请求委派给处理器链。
具体来说,以上代码的执行流程如下:
-
Client 创建了一个处理器链:ConcreteHandler1(ConcreteHandler2(ConcreteHandler3(DefaultHandler())))。
-
Client 将一系列请求 [2, 5, 14, 22, 18, 3, 35, 27, 20] 委派给处理器链。
-
处理器链开始处理请求。首先,ConcreteHandler1 尝试处理请求 2,但由于该请求不在它的处理范围内,它将请求传递给下一个处理器 ConcreteHandler2。
-
ConcreteHandler2 尝试处理请求 2,但仍然无法处理,于是将请求传递给下一个处理器 ConcreteHandler3。
-
ConcreteHandler3 尝试处理请求 2,同样无法处理,于是将请求传递给下一个处理器 DefaultHandler。
-
DefaultHandler 处理请求 2,并输出日志:"End of chain, no handler for 2"。
-
处理器链继续处理请求。ConcreteHandler1 尝试处理请求 5,成功处理,并输出日志:"Request 5 handled in handler 1"。
-
ConcreteHandler1 继续处理请求 14,但由于该请求不在它的处理范围内,它将请求传递给下一个处理器 ConcreteHandler2。
-
ConcreteHandler2 成功处理请求 14,并输出日志:"Request 14 handled in handler 2"。
-
ConcreteHandler2 继续处理请求 22,但由于该请求不在它的处理范围内,它将请求传递给下一个处理器 ConcreteHandler3。
-
ConcreteHandler3 成功处理请求 22,并输出日志:"Request 22 handled in handler 3"。
-
ConcreteHandler3 继续处理请求 18,但由于该请求不在它的处理范围内,它将请求传递给下一个处理器 DefaultHandler。
-
DefaultHandler 成功处理请求 18,并输出日志:"End of chain, no handler for 18"。
以此类推,即可得到最后结果。
ConcreteHandler1(ConcreteHandler2(ConcreteHandler3(DefaultHandler())))
本句代码解释:
具体来说,它使用了装饰器模式(Decorator Pattern)来实现责任链(Chain of Responsibility)模式。
在责任链模式中,每个处理器(Handler)都可以处理一个请求,如果它不能处理这个请求,就把请求传递给下一个处理器,直到有一个处理器能够处理为止。在这个代码片段中,ConcreteHandler1、ConcreteHandler2、ConcreteHandler3、DefaultHandler 都是处理器,它们都继承自同一个 Handler 父类,并且按照一定的顺序组合在一起,形成了一个责任链。
具体来说,这个代码片段的意思是:
-
DefaultHandler 是最底层的处理器,也就是整个责任链的终点。如果所有的处理器都不能处理请求,那么就会由 DefaultHandler 来处理请求。
-
ConcreteHandler3 继承自 Handler,并重写了处理请求的方法。如果 ConcreteHandler3 不能处理请求,那么就会将请求传递给它的下一个处理器。
-
ConcreteHandler2 继承自 ConcreteHandler3,并重写了处理请求的方法。如果 ConcreteHandler2 不能处理请求,那么就会将请求传递给它的下一个处理器,也就是 ConcreteHandler3。
-
ConcreteHandler1 继承自 ConcreteHandler2,并重写了处理请求的方法。如果 ConcreteHandler1 不能处理请求,那么就会将请求传递给它的下一个处理器,也就是 ConcreteHandler2。
因此,当一个请求到达 ConcreteHandler1 时,它会首先尝试由 ConcreteHandler1 来处理,如果不能处理,则会传递给 ConcreteHandler2,然后是 ConcreteHandler3,最后是 DefaultHandler。