Python责任链模式介绍、使用方法

news/2024/10/30 13:35:11/

一、Python责任链模式介绍

概念:

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,用于将请求从一个对象传递到另一个对象,直到请求被处理为止。在责任链模式中,多个对象组成一个链,每个对象都有机会处理请求,如果一个对象不能处理请求,它会将请求传递给链中的下一个对象,直到请求被处理为止。

功能:

责任链模式的主要功能是将请求从一个对象传递到另一个对象,直到请求被处理为止。这种模式能够让多个对象共同处理请求,从而实现请求的处理分担和简化。

优点:

  1. 降低系统耦合度:责任链模式将请求发送者和请求处理者解耦,使多个对象都有机会处理请求,从而降低系统的耦合度。

  2. 灵活性好:责任链模式可以动态地组合和增加责任的对象,从而使系统更加灵活。

  3. 可扩展性好:责任链模式可以方便地扩展新的请求处理者,从而增强系统的可扩展性。

缺点:

  1. 处理请求可能不确定:由于责任链中的请求处理者是动态的,因此请求可能被多个处理者处理,从而可能导致最终的请求处理结果不确定。

  2. 性能问题:如果责任链中的处理者过多,可能会影响系统的性能。

应用场景:

  1. 请求需要被多个对象处理时,而且每个对象处理请求的方式不同。

  2. 在系统中需要动态地增加或删除请求处理者时。

  3. 在系统中需要分担和简化请求处理时。

使用方式:

  1. 定义一个请求基类,提供设置请求和获取请求的方法。

  2. 定义一个处理请求的抽象基类,提供处理请求的方法,并包含一个指向下一个处理者的指针。

  3. 定义具体的处理请求的类,并继承抽象基类,实现处理请求的方法。

  4. 在客户端代码中组合处理请求的链,并发送请求。

在应用程序开发中的应用:

责任链模式在日常开发中比较常见,如:

  1. Servlet过滤器链:Java Web应用中,通常使用Servlet过滤器链来处理请求。

  2. Android事件分发机制:在Android开发中,事件分发机制使用责任链模式来处理事件。

  3. 企业流程管理系统(BPM):BPM系统中,流程处理通常采用责任链模式来处理流程请求。

二、责任链模式使用

工作原理:

责任链模式的工作原理如下:

  1. 将多个对象组成一个链,在链中依次排列。

  2. 当一个请求到达链的起始点时,首先由第一个对象处理请求,如果该对象可以处理请求,则处理请求并结束;否则,将请求传递给链中的下一个对象。

  3. 如果下一个对象可以处理请求,则处理请求并结束;否则,将请求继续传递给链中的下一个对象,直到请求被处理为止。

  4. 如果整个链上的所有对象都不能处理请求,则请求将被丢弃。

示例一:实现多部门处理请求功能

假设一个公司有多个部门,包括人事部门、财务部门和销售部门,而这些部门都有权限审批员工的假期申请。如果员工提交假期申请,请求需要从人事部门开始审批,如果人事部门无法处理请求,则将请求传递给下一个部门。如果所有部门都无法处理请求,则请求将被丢弃。

以下是该示例的具体实现:

  1. 创建请求类:
  2. 创建抽象基类:
  3. 创建具体部门类:
  4. 使用责任链模式:
# 定义请求类
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.

使用方法:

  1. 创建请求类,并在类中定义请求的属性(如上述示例中的姓名和天数)。

  2. 创建抽象基类,并在类中定义设置和处理下一个部门的抽象方法。

  3. 创建具体部门类,并继承抽象基类,实现设置和处理下一个部门的方法。在处理方法中,如果当前部门可以处理请求,则处理请求并结束;否则调用下一个部门的处理方法,继续处理请求。

  4. 在客户端代码中组合部门,并设置每个部门的下一个部门。最后,将请求发送给第一个部门,让它开始处理请求。

示例二:实现动态处理多种类反馈功能

假设我们正在开发一个网站,该网站提供了一个匿名用户反馈的功能,用户可以提交反馈表单来对网站进行评价。在提交反馈表单后,我们需要一个处理程序去处理反馈并给出相应的处理结果。

由于处理程序的种类可能比较多,我们可以采用责任链模式来实现动态增加或删除请求处理者的场景。具体实现步骤如下:

  1. 首先定义一个抽象基类 FeedbackHandler,该基类包含两个抽象方法:handle 用于处理反馈,set_next 用于设置下一个处理程序。
  2. 然后我们定义具体的处理程序类,例如 TechnicalSupportHandlerQualityControlHandlerCustomerServiceHandler。这些类都实现了 FeedbackHandler 抽象基类中的抽象方法,并且都有一个下一个处理程序变量。
  3. 最后,我们可以用一个反馈处理链来连接这些处理程序,并定义一个客户端类来提交反馈表单。客户端类将首先将反馈提交给处理链的第一个处理程序,如果该程序不能处理反馈,则将其传递给链中下一个处理程序,以此类推。代码如下:

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 的方式来定义。


http://www.ppmy.cn/news/991439.html

相关文章

Java多线程(二)

目录 一、多进程 二、多线程 三、多线程与多进程的区别与联系 一、多进程 为了实现支持多个任务的系统&#xff0c;这里就设计了进程&#xff0c;用于实现并发编程的效果。由于进程需要频繁的创建和销毁&#xff0c;这里就导致了进程&#xff1a;消耗的资源多、速度慢。开销大主…

Linux近两年高危漏洞修复过程记录

一、背景 2023年8月份&#xff0c;面对即将到来的“大运会”、“亚运会”&#xff0c;今年的例行安全护网阶段也将迎来新的挑战和时刻&#xff0c;为此相关部门发布了国家级实战攻防演练已进入紧急「备战」时刻&#xff01;这里我们主要说一下Linux OS层面的漏洞处理&#xff0…

网络运维基础问题及解答

前言 本篇文章是对于网络运维基础技能的一些常见问题的解答&#xff0c;希望能够为进行期末复习或者对网络运维感兴趣的同学或专业人员提供一定的帮助。 问题及解答 1. 列举 3 种常用字符编码&#xff0c;简述怎样在 str 和 bytes 之间进行编码和解码。 答&#xff1a;常用的…

增量预训练baichuan-13b-chat遇到的那些坑

文章目录 前言资源deepspeed一、训练的坑二、推理的坑三、继续训练的坑总结前言 资源 单机两4090,如图 单卡24G,baichuan-13b-chat单卡推理需要至少26G,因此仅用一张卡,我们是无法加载百川13B的模型,所以,无论是推理还是训练,我们都必须并行! deepspeed 核心思想…

Pytorch个人学习记录总结 09

目录 损失函数与反向传播 L1Loss MSELOSS CrossEntropyLoss 损失函数与反向传播 所需的Loss计算函数都在torch.nn的LossFunctions中&#xff0c;官方网址是&#xff1a;torch.nn — PyTorch 2.0 documentation。举例了L1Loss、MSELoss、CrossEntropyLoss。 在这些Loss函数…

Unity 性能优化五:渲染模块压力

CPU压力 Batching 在GPU渲染前&#xff0c;CPU会把数据按batch发送给GPU&#xff0c;每发送一次&#xff0c;都是一个drawcall&#xff0c;GPU在渲染每个batch的时候&#xff0c;会切换渲染状态&#xff0c;这里的渲染状态指的是&#xff1a;影响对象在屏幕上的外观的渲染属性…

Python实现指定区域桌面变化监控并报警

在这篇博客中&#xff0c;我们将使用Python编程语言和一些常用的库来实现一个简单的区域监控和变化报警系统。我们将使用Tkinter库创建一个图形界面&#xff0c;允许用户选择监控区域&#xff0c;并使用OpenCV库进行图像处理和相似性比较&#xff0c;以检测区域内的变化&#x…

中文大模型评估数据集——C-Eval

C-EVAL: A Multi-Level Multi-Discipline Chinese Evaluation Suite for Foundation Models https://arxiv.org/pdf/2305.08322v1.pdfhttps://github.com/SJTU-LIT/cevalhttps://cevalbenchmark.com/static/leaderboard.html Part1 前言 怎么去评估一个大语言模型呢? 在广泛…