一、Python责任链模式介绍
概念:
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,用于将请求从一个对象传递到另一个对象,直到请求被处理为止。在责任链模式中,多个对象组成一个链,每个对象都有机会处理请求,如果一个对象不能处理请求,它会将请求传递给链中的下一个对象,直到请求被处理为止。
功能:
责任链模式的主要功能是将请求从一个对象传递到另一个对象,直到请求被处理为止。这种模式能够让多个对象共同处理请求,从而实现请求的处理分担和简化。
优点:
-
降低系统耦合度:责任链模式将请求发送者和请求处理者解耦,使多个对象都有机会处理请求,从而降低系统的耦合度。
-
灵活性好:责任链模式可以动态地组合和增加责任的对象,从而使系统更加灵活。
-
可扩展性好:责任链模式可以方便地扩展新的请求处理者,从而增强系统的可扩展性。
缺点:
-
处理请求可能不确定:由于责任链中的请求处理者是动态的,因此请求可能被多个处理者处理,从而可能导致最终的请求处理结果不确定。
-
性能问题:如果责任链中的处理者过多,可能会影响系统的性能。
应用场景:
-
请求需要被多个对象处理时,而且每个对象处理请求的方式不同。
-
在系统中需要动态地增加或删除请求处理者时。
-
在系统中需要分担和简化请求处理时。
使用方式:
-
定义一个请求基类,提供设置请求和获取请求的方法。
-
定义一个处理请求的抽象基类,提供处理请求的方法,并包含一个指向下一个处理者的指针。
-
定义具体的处理请求的类,并继承抽象基类,实现处理请求的方法。
-
在客户端代码中组合处理请求的链,并发送请求。
在应用程序开发中的应用:
责任链模式在日常开发中比较常见,如:
-
Servlet过滤器链:Java Web应用中,通常使用Servlet过滤器链来处理请求。
-
Android事件分发机制:在Android开发中,事件分发机制使用责任链模式来处理事件。
-
企业流程管理系统(BPM):BPM系统中,流程处理通常采用责任链模式来处理流程请求。
二、责任链模式使用
工作原理:
责任链模式的工作原理如下:
-
将多个对象组成一个链,在链中依次排列。
-
当一个请求到达链的起始点时,首先由第一个对象处理请求,如果该对象可以处理请求,则处理请求并结束;否则,将请求传递给链中的下一个对象。
-
如果下一个对象可以处理请求,则处理请求并结束;否则,将请求继续传递给链中的下一个对象,直到请求被处理为止。
-
如果整个链上的所有对象都不能处理请求,则请求将被丢弃。
示例一:实现多部门处理请求功能
假设一个公司有多个部门,包括人事部门、财务部门和销售部门,而这些部门都有权限审批员工的假期申请。如果员工提交假期申请,请求需要从人事部门开始审批,如果人事部门无法处理请求,则将请求传递给下一个部门。如果所有部门都无法处理请求,则请求将被丢弃。
以下是该示例的具体实现:
- 创建请求类:
- 创建抽象基类:
- 创建具体部门类:
- 使用责任链模式:
# 定义请求类
class LeaveRequest():def __init__(self, name, days):self.name = nameself.days = daysfrom abc import ABCMeta, abstractmethod# 定义抽象基类
class Department(metaclass=ABCMeta):@abstractmethoddef set_next(self, department):pass@abstractmethoddef handle(self, request):pass# 定义具体实现类。 三个部门
class HRDepartment(Department):def set_next(self, department):self.next_department = departmentdef handle(self, request):if request.days <= 5:print(f"HR approves {request.name}'s leave request for {request.days} days.")else:self.next_department.handle(request)class FinanceDepartment(Department):def set_next(self, department):self.next_department = departmentdef handle(self, request):if request.days <= 10:print(f"Finance approves {request.name}'s leave request for {request.days} days.")else:self.next_department.handle(request)class SalesDepartment(Department):def set_next(self, department):self.next_department = departmentdef handle(self, request):if request.days <= 15:print(f"Sales approves {request.name}'s leave request for {request.days} days.")else:print(f"All departments cannot handle {request.name}'s leave request for {request.days} days.")# 创建责任链
hr = HRDepartment()
finance = FinanceDepartment()
sale = SalesDepartment()hr.set_next(finance)
finance.set_next(sale)# 创建请求
req1 = LeaveRequest("name1", 3)
hr.handle(req1)req2 = LeaveRequest("name2", 8)
hr.handle(req2)req3 = LeaveRequest("name3", 13)
hr.handle(req3)req4 = LeaveRequest("name4", 30)
hr.handle(req4)
运行结果:
HR approves name1's leave request for 3 days.
Finance approves name2's leave request for 8 days.
Sales approves name3's leave request for 13 days.
All departments cannot handle name4's leave request for 30 days.
使用方法:
-
创建请求类,并在类中定义请求的属性(如上述示例中的姓名和天数)。
-
创建抽象基类,并在类中定义设置和处理下一个部门的抽象方法。
-
创建具体部门类,并继承抽象基类,实现设置和处理下一个部门的方法。在处理方法中,如果当前部门可以处理请求,则处理请求并结束;否则调用下一个部门的处理方法,继续处理请求。
-
在客户端代码中组合部门,并设置每个部门的下一个部门。最后,将请求发送给第一个部门,让它开始处理请求。
示例二:实现动态处理多种类反馈功能
假设我们正在开发一个网站,该网站提供了一个匿名用户反馈的功能,用户可以提交反馈表单来对网站进行评价。在提交反馈表单后,我们需要一个处理程序去处理反馈并给出相应的处理结果。
由于处理程序的种类可能比较多,我们可以采用责任链模式来实现动态增加或删除请求处理者的场景。具体实现步骤如下:
- 首先定义一个抽象基类
FeedbackHandler
,该基类包含两个抽象方法:handle
用于处理反馈,set_next
用于设置下一个处理程序。 - 然后我们定义具体的处理程序类,例如
TechnicalSupportHandler
、QualityControlHandler
和CustomerServiceHandler
。这些类都实现了FeedbackHandler
抽象基类中的抽象方法,并且都有一个下一个处理程序变量。 - 最后,我们可以用一个反馈处理链来连接这些处理程序,并定义一个客户端类来提交反馈表单。客户端类将首先将反馈提交给处理链的第一个处理程序,如果该程序不能处理反馈,则将其传递给链中下一个处理程序,以此类推。代码如下:
from abc import ABC, abstractmethod# 定义抽象基类
class FeedbackHandler():@abstractmethoddef handle(self, feedback):pass@abstractmethoddef set_next(self, handler):pass# 定义具体实现类。3个
class TechnicalSupportHandler(FeedbackHandler):def __init__(self):self.next_handler = Nonedef set_next(self, handler):self.next_handler = handlerdef handle(self, feedback):if feedback.severity == "minor":return f"Handled by technical with priority: {feedback.severity}"else:if self.next_handler:return self.next_handler.handle(feedback)class QualityControlHandler(FeedbackHandler):def __init__(self):self.next_handler = Nonedef set_next(self, handler):self.next_handler = handlerdef handle(self, feedback):if feedback.severity == "major":return f"Handled by quality with priority: {feedback.severity}"else:if self.next_handler:return self.next_handler.handle(feedback)class CustomerServiceHandler(FeedbackHandler):def __init__(self):self.next_handler = Nonedef set_next(self, handler):self.next_handler = handlerdef handle(self, feedback):if feedback.severity == "critical":return f"Handled by custom with priority: {feedback.severity}"else:if self.next_handler:return self.next_handler.handle(feedback)# 定义反馈处理链
class Feedback():def __init__(self,severity,priority):self.severity = severityself.priority = priorityclass FeedbackProcessor():def __init__(self):self.handler = Nonedef add_handler(self, handler):if not self.handler:self.handler = handlerelse:current_handler = self.handlerwhile current_handler.next_handler:current_handler = current_handler.next_handlercurrent_handler.next_handler = handlerdef process_feedback(self, feedback):return self.handler.handle(feedback)# 创建实例
processor = FeedbackProcessor()
processor.add_handler(TechnicalSupportHandler())
processor.add_handler(QualityControlHandler())
processor.add_handler(CustomerServiceHandler())feedback = Feedback("minor", "low")
res = processor.process_feedback(feedback)
print(res)feedback = Feedback("major", "medium")
res = processor.process_feedback(feedback)
print(res)feedback = Feedback("critical", "high")
res = processor.process_feedback(feedback)
print(res)
运行结果:
Handled by technical with priority: minor
Handled by quality with priority: major
Handled by custom with priority: critical
在这个例子中,我们首先定义了一个 Feedback
类来表示反馈表单,其中包含两个属性,一个是反馈的严重程度,一个是反馈的优先级。然后,我们定义了一个 FeedbackProcessor
类来处理反馈表单。在 FeedbackProcessor
类中,我们可以动态地增加或删除处理者,通过 add_handler
方法来添加一个处理程序,这个方法会将处理程序添加到责任链的最后面。在 process_feedback
方法中,我们将反馈表单传递给责任链的第一个处理程序,然后依次将反馈传递给链中的下一个处理程序,直到有一个处理程序可以处理该反馈为止。
责任链模式的优点是可以动态地增加或删除请求处理者,同时也降低了请求处理者与客户端之间的耦合度。缺点是由于每个请求都需要依次传递给链中的处理程序,所以可能会造成额外的处理延迟。这种模式适用于处理多个处理程序并且处理程序之间具有一定的顺序关系的场景,例如在处理异常时,可以使用责任链模式来处理错误。
解释:metaclass=ABCMeta
class Department(metaclass=ABCMeta)
和 class FeedbackHandler(): @abstractmethod
都是Python中用于实现抽象类或接口的语法结构。
class Department(metaclass=ABCMeta)
表示定义了一个名为 Department
的类,它是一个抽象基类,并且使用 ABCMeta
元类来定义。元类是用于定义类的类,它可以在定义类时动态地修改类的行为,例如在这里,我们使用元类来定义抽象基类,这样就可以规定该类的子类必须实现一些特定的方法,否则会报错。
class FeedbackHandler(): @abstractmethod
则是使用了Python的装饰器语法,在 FeedbackHandler
类中定义了一个抽象方法 handle
。该方法使用了 @abstractmethod
装饰器,表示该方法是一个抽象方法,必须由子类重写实现,否则在实例化子类时会抛出异常。
这两种语法结构都用于实现Python中的抽象类或接口,它们的区别在于:
class Department(metaclass=ABCMeta)
是使用元类来定义抽象基类,它可以规定该类的子类必须实现特定的方法或属性,否则会报错。class FeedbackHandler(): @abstractmethod
是使用装饰器来定义抽象方法,在子类中必须重写实现该方法,否则会抛出异常。
通常情况下,如果需要定义一个包含多个抽象方法的抽象类,我们会选择使用 class Department(metaclass=ABCMeta)
的方式来定义,而如果只需要定义一个抽象方法,我们会选择使用 class FeedbackHandler(): @abstractmethod
的方式来定义。