Django信号与扩展:深入理解与实践
title: Django信号与扩展:深入理解与实践
date: 2024/5/15 22:40:52
updated: 2024/5/15 22:40:52
categories:
- 后端开发
tags:
- Django
- 信号
- 松耦合
- 观察者
- 扩展
- 安全
- 性能
第一部分:Django信号基础
Django信号概述
一. Django信号的定义与作用
Django信号(Signal)是Django框架中的一种机制,用于在特定事件发生时进行通信。信号可以让不同的Django组件松耦合地通信,即使它们不直接相互依赖。这种松耦合的设计使得Django应用更加灵活、可扩展和可维护。
Django信号分为内置信号和自定义信号。内置信号是由Django框架提供的,在Django内部使用,如模型保存、删除、数据库操作等。自定义信号是开发者根据需要创建的信号,用于在自定义事件发生时进行通信。
信号的主要作用包括:
- 解耦组件:信号允许不同的组件在不直接依赖的情况下进行通信,使得组件之间的耦合度降低,提高了代码的可重用性和可维护性。
- 事件监听:信号可以被监听器(Signal Receiver)监听,监听器可以在特定事件发生时执行相应的动作。
- 扩展框架:信号可以用于扩展Django框架,开发者可以在特定事件发生时执行自定义逻辑,实现对Django框架的定制和扩展。
二. Django信号与观察者模式的对比
Django信号和观察者模式(Observer Pattern)都是解决松耦合通信问题的设计模式。它们的主要区别在于实现方式和应用场景。
-
实现方式:
- Django信号采用广播机制,信号发送者不需要知道谁在监听信号。信号发送者只需要发送信号,而信号接收者只需要注册自己感兴趣的信号。
- 观察者模式采用一对多的关系,观察者(Observer)直接订阅主题(Subject)。当主题状态发生变化时,主题会通知所有订阅者。
-
应用场景:
- Django信号适用于Django框架内部的松耦合通信,例如在模型保存、删除、数据库操作等事件发生时进行通信。
- 观察者模式适用于更广泛的场景,例如GUI应用、网络编程、事件驱动编程等领域。
信号的注册与接收
一. 信号的注册与接收
在Django中,信号的注册与接收主要通过以下两个步骤完成:
- 创建信号接收器(Signal Receiver):信号接收器是一个函数,用于在特定信号发生时执行相应的动作。信号接收器需要接收一个sender参数,用于标识信号的发送者。
- 注册信号接收器:将信号接收器与特定信号关联起来,以便在信号发生时调用信号接收器。
二. 内置信号的介绍
Django框架提供了一些内置信号,用于在特定事件发生时进行通信。以下是一些常用的内置信号:
- django.db.models.signals.pre_save:在模型保存前发送。
- django.db.models.signals.post_save:在模型保存后发送。
- django.db.models.signals.pre_delete:在模型删除前发送。
- django.db.models.signals.post_delete:在模型删除后发送。
- django.db.models.signals.m2m_changed:在模型多对多关系发生变化时发送。
三. 自定义信号的创建
要创建自定义信号,需要使用Django的Signal类。以下是创建自定义信号的示例:
from django.dispatch import Signal# 创建自定义信号
custom_signal = Signal(providing_args=["arg1", "arg2"])
在上面的示例中,我们创建了一个名为custom_signal的自定义信号,并指定了两个参数arg1和arg2。
四. 信号接收器的编写与注册
- 编写信号接收器:信号接收器是一个函数,用于在特定信号发生时执行相应的动作。信号接收器需要接收一个sender参数,用于标识信号的发送者。
def custom_signal_receiver(sender, arg1, arg2, **kwargs):# 执行相应的动作pass
- 注册信号接收器:将信号接收器与特定信号关联起来,以便在信号发生时调用信号接收器。
custom_signal.connect(custom_signal_receiver, sender=SomeModel)
在上面的示例中,我们将custom_signal_receiver函数注册为custom_signal信号的接收器,并指定SomeModel为信号的发送者。当custom_signal信号发生时,custom_signal_receiver函数将被调用。
信号的发送与处理
一. 信号的注册与接收
信号的注册和接收是通过django.dispatch.dispatcher.Signal类实现的。下面是注册和接收信号的基本步骤:
- 导入信号:首先需要导入需要使用的信号,例如内置信号
django.db.models.signals.post_save。 - 创建接收器:接收器是一个函数,当信号触发时,该函数会被调用。接收器函数接收一个参数,即信号对象,其他参数根据信号定义而定。
- 注册接收器:使用
connect方法将接收器函数注册到信号上。connect方法接收两个参数:第一个参数是信号对象,第二个参数是接收器函数。
以下是一个简单的信号注册和接收示例:
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import MyModel@receiver(post_save, sender=MyModel)
def my_receiver(sender, instance, **kwargs):print("MyModel saved!")# Register the receiver
post_save.connect(my_receiver, sender=MyModel)
二. 内置信号的介绍
Django提供了许多内置信号,可以在特定事件发生时触发。下面是一些常用的内置信号:
django.db.models.signals.pre_save:在模型实例被保存前触发。django.db.models.signals.post_save:在模型实例被保存后触发。django.db.models.signals.pre_delete:在模型实例被删除前触发。django.db.models.signals.post_delete:在模型实例被删除后触发。django.db.models.signals.m2m_changed:在多对多关系发生变化时触发。
三. 自定义信号的创建
自定义信号可以使用django.dispatch.dispatcher.Signal类创建。下面是创建自定义信号的步骤:
- 导入
Signal类。 - 创建自定义信号:创建一个信号对象,并指定信号名称和描述。
- 注册自定义信号:使用
connect方法将接收器函数注册到自定义信号上。
以下是一个创建自定义信号示例:
from django.dispatch import Signalmy_signal = Signal(providing_args=["arg1", "arg2"])def my_receiver(sender, arg1, arg2, **kwargs):print("MySignal received, arg1=%s, arg2=%s" % (arg1, arg2))# Register the receiver
my_signal.connect(my_receiver)# Trigger the signal
my_signal.send(sender=None, arg1="value1", arg2="value2")
四. 信号接收器的编写与注册
信号接收器是一个函数,当信号触发时,该函数会被调用。信号接收器函数接收一个参数,即信号对象,其他参数根据信号定义而定。
信号接收器可以使用@receiver装饰器注册,如下所示:
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import MyModel@receiver(post_save, sender=MyModel)
def my_receiver(sender, instance, **kwargs):print("MyModel saved!")# Register the receiver
post_save.connect(my_receiver, sender=MyModel)
也可以使用connect方法手动注册,如下所示:
from django.db.models.signals import post_save
from myapp.models import MyModeldef my_receiver(sender, instance, **kwargs):print("MyModel saved!")# Register the receiver
post_save.connect(my_receiver, sender=MyModel)
需要注意的是,在使用@receiver装饰器注册接收器时,信号会自动解除对该接收器的引用,因此在使用@receiver装饰器注册接收器时,不需要手动解除接收器的注册。
第二部分:Django信号的高级应用
信号的优化与调试
- 信号的性能考量
信号处理可能会对应用程序的性能产生影响,特别是在处理大量数据或高并发场景时。为了优化信号性能,可以采取以下措施:
- 限制信号接收器的数量:只注册必要的信号接收器,避免不必要的处理。
- 使用异步信号处理:如前所述,可以使用
django_q等工具实现异步信号处理,以提高应用程序的性能。 - 避免在信号接收器中执行耗时操作:信号接收器应尽量简洁,避免执行耗时的数据库查询、网络请求等操作。
- 信号的调试技巧
AD:漫画首页
在调试信号时,可以采取以下技巧:
- 使用断点:在信号接收器中设置断点,以便在信号触发时暂停执行,检查变量值和调用堆栈。
- 打印日志:在信号接收器中添加日志记录,以便在运行时查看信号处理过程。
- 使用Django Debug Toolbar:Django Debug Toolbar是一个强大的调试工具,可以显示有关请求、响应和信号处理的各种信息。
- 信号的错误处理与日志记录
在处理信号时,可能会遇到错误。为了更好地处理错误和记录日志,可以采取以下措施:
- 异常处理:在信号接收器中使用
try...except语句捕获异常,并进行相应的处理。
def custom_signal_receiver(sender, **kwargs):try:# 执行相应的动作passexcept Exception as e:# 处理异常print(f"Error in custom_signal_receiver: {str(e)}")
- 日志记录:使用Python内置的
logging模块或Django的django.utils.log模块记录日志。
import loggingdef custom_signal_receiver(sender, **kwargs):logger = logging.getLogger(__name__)try:# 执行相应的动作passexcept Exception as e:# 记录错误日志logger.error(f"Error in custom_signal_receiver: {str(e)}")
通过以上措施,可以更好地优化、调试和处理信号,确保应用程序的稳定性和性能。
信号在Django应用中的实践
- 用户认证与权限管理中的信号应用
在用户认证和权限管理方面,Django信号可以用于在用户创建、更新或删除时执行特定的操作。以下是一些示例:
- 用户创建时发送欢迎邮件:
from django.core.mail import send_mail
from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver@receiver(user_logged_in, sender=User)
def send_welcome_email(sender, user, request, **kwargs):subject = '欢迎加入我们的网站!'message = '感谢您注册我们的网站,祝您使用愉快!'from_email = settings.DEFAULT_FROM_EMAILrecipient_list = [user.email]send_mail(subject, message, from_email, recipient_list)
- 用户权限变更时更新缓存:
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.contrib.auth.models import User@receiver(post_save, sender=User)
def update_permissions_cache(sender, instance, created, **kwargs):if not created:# 更新用户权限缓存pass@receiver(post_delete, sender=User)
def clear_permissions_cache(sender, instance, **kwargs):# 清除用户权限缓存pass
- 模型生命周期中的信号应用
在模型生命周期中,Django信号可以用于在模型实例创建、更新或删除时执行特定的操作。以下是一些示例:
- 创建模型实例时自动生成唯一标识符:
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .models import MyModel@receiver(pre_save, sender=MyModel)
def generate_unique_identifier(sender, instance, **kwargs):if not instance.unique_identifier:instance.unique_identifier = generate_unique_id()
- 删除模型实例时级联删除相关联的数据:
from django.db.models.signals import post_delete
from django.dispatch import receiver
from .models import MyModel@receiver(post_delete, sender=MyModel)
def cascade_delete(sender, instance, **kwargs):# 删除与instance相关联的数据pass
- 信号在第三方应用中的集成
AD:专业搜索引擎
在集成第三方应用时,Django信号可以用于在第三方应用执行特定操作时触发自定义逻辑。以下是一些示例:
- 在第三方博客应用中,当文章发布时通知其他用户:
from django.db.models.signals import post_save
from django.dispatch import receiver
from third_party_app.models import BlogPost@receiver(post_save, sender=BlogPost)
def notify_users(sender, instance, created, **kwargs):if created:# 通知其他用户有新文章发布pass
- 在第三方电子商务应用中,当订单支付成功时更新库存:
from django.db.models.signals import post_save
from django.dispatch import receiver
from third_party_app.models import Order@receiver(post_save, sender=Order)
def update_inventory(sender, instance, created, **kwargs):if instance.payment_status == 'paid':# 更新库存pass
通过在Django应用中实践信号,可以实现更灵活、可扩展的逻辑,提高代码的可维护性和可读性。
信号的安全性与最佳实践:
-
安全隐患与防范:
- 信号滥用:避免在信号处理函数中执行过于复杂的操作,这可能导致性能问题,甚至安全漏洞,比如在信号处理中执行SQL注入攻击。
- 权限控制:确保信号处理函数只由有权限的用户或特定角色执行,防止未经授权的访问。
- 数据同步:在处理敏感数据时,确保数据在信号处理过程中得到恰当的加密和保护,防止数据泄露。
- 避免循环依赖:避免在信号中引发其他信号,这可能导致无限循环,影响系统稳定。
-
最佳实践与编码规范:
- 明确信号目的:为每个信号定义清晰的目的,确保信号处理函数只执行与信号相关的任务。
- 分段处理:将信号处理函数分解为小的、可测试的部分,便于维护和调试。
- 使用@receiver装饰器:在需要的地方使用装饰器来注册信号处理函数,这样更容易管理和控制信号的使用。
- 使用weakref:对于长时间运行的任务,使用
weakref可以防止内存泄漏,因为信号接收器会在信号不再被使用时自动卸载。 - 信号订阅选择性:只订阅真正需要的信号,避免不必要的性能消耗。
- 异常处理:在信号处理函数中妥善处理可能出现的异常,防止异常传播到其他部分。
- 文档注释:为信号、接收器和处理函数提供清晰的文档,以便其他开发人员理解其作用和使用方式。
遵循这些最佳实践,可以确保信号在Django应用中的安全和高效使用。
附录
Django 信号 API 参考:
Django 信号提供了一种在框架内部或第三方应用之间进行低级别通信的机制。以下是一些主要的 API 函数和类:
AD:首页 | 一个覆盖广泛主题工具的高效在线平台
signal.signal(signal, receiver):注册一个信号接收器函数。signal.send(signal, *args, **kwargs):发送信号。signal.get_receivers(signal):获取所有已经注册的接收器。signal.disconnect(receiver, sender, dispatch_uid):解除接收器和信号的连接。signal.connect(receiver, sender, weak=True, dispatch_uid=None):连接一个接收器到信号上。
Django 扩展资源列表:
以下是一些常用的 Django 扩展和第三方应用,可以帮助开发人员提高工作效率和增强应用功能:
- django-debug-toolbar:一个 Django 调试工具,提供有关请求、视图、模板、SQL 查询、缓存等方面的信息。
- django-extensions:提供一些有用的 Django 管理命令和扩展,如自动生成 South 数据库迁移、shell_plus 和其他实用工具。
- django-crispy-forms:一个 Django 应用,可以让你更轻松地控制表单的渲染方式。
- django-rest-framework:一个 Django 的 RESTful API 框架,使得构建 Web API 更加简单。
- django-filter:一个 Django 应用,为 ListView 和 GenericView 提供了强大的过滤功能。
Django 社区与支持:
- Django 官方网站:提供 Django 框架的最新资讯、文档和下载。
- Django 中文社区:提供 Django 中文文档、教程、视频、问答等资源。
- Django Software Foundation:Django 的官方非盈利组织,提供 Django 开发和维护的资金支持。
- Django 问答社区:一个 Django 社区问答平台,可以在上面寻求帮助和分享经验。
- Django Stack Overflow:一个关于 Django 的问答社区,可以在上面寻求帮助和分享经验。
- Django 包索引:一个 Django 包和应用的搜索引擎,可以在上面找到适合你需求的扩展和工具。
相关文章:
Django信号与扩展:深入理解与实践
title: Django信号与扩展:深入理解与实践 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 后端开发 tags: Django信号松耦合观察者扩展安全性能 第一部分:Django信号基础 Django信号概述 一. Django信号的定义与作用 Django信…...
使用Docker创建verdaccio私服
verdaccio官网 1.Docker安装 这边以Ubuntu安装为例Ubuntu 安装Docker,具体安装方式请根据自己电脑自行搜索。 2.下载verdaccio docker pull verdaccio/verdaccio3.运行verdaccio 运行容器: docker run -it -d --name verdaccio -p 4873:4873 ver…...
Spring 使用 Groovy 实现动态server
本人在项目中遇到这么个需求,有一个模块的server方法需要频繁修改 经阅读可以使用 Groovy 使用java脚本来时pom坐标 <dependency><groupId>org.codehaus.groovy</groupId><artifactId>groovy</artifactId><version>3.0.9</version>…...
oracle不得不知道的sql
一、oracle 查询语句 1.translate select translate(abc你好cdefgdc,abcdefg,1234567)from dual; select translate(abc你好cdefgdc,abcdefg,)from dual;--如果替换字符整个为空字符 ,则直接返回null select translate(abc你好cdefgdc,abcdefg,122)from dual; sel…...
算法-卡尔曼滤波之卡尔曼滤波的第二个方程:预测方程(状态外推方程)
在上一节中,使用了静态模型,我们推导出了卡尔曼滤波的状态更新方程,但是在实际情况下,系统都是动态,预测阶段,前后时刻的状态是改变的,此时我们引入预测方程,也叫状态外推方程&#…...
刘邦的创业团队是沛县人,朱元璋的则是凤阳;要创业,一个县人才就够了
当人们回顾刘邦和朱元璋的创业经历时,总是会感慨他们起于微末,都创下了偌大王朝,成就无上荣誉。 尤其是我们查阅史书时,发现这二人的崛起班底都是各自的家乡人,例如刘邦的班底就是沛县人,朱元璋的班底是凤…...
【Unity之FairyGUI】你了解FGUI吗,跨平台多功能高效UI插件
👨💻个人主页:元宇宙-秩沅 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 秩沅 原创 👨💻 收录于专栏:就业…...
基于51单片机的自动浇花器电路
一、系统概述 自动浇水灌溉系统设计方案,以AT89C51单片机为控制核心,采用模块化的设计方法。 组成部分为:5V供电模块、土壤湿度传感器模块、ADC0832模数转换模块、水泵控制模块、按键输入模块、LCD显示模块和声光报警模块,结构如…...
2024中国(重庆)商旅文化川渝美食暨消费品博览会8月举办
2024中国(重庆)商旅文化川渝美食暨消费品博览会8月举办 邀请函 主办单位: 中国航空学会 重庆市南岸区人民政府 招商执行单位: 重庆港华展览有限公司 展会背景: 2024中国航空科普大会暨第八届全国青少年无人机大赛在重庆举办ÿ…...
MacOS docker 安装与配置
orbstack 安装 官网: https://orbstack.dev 下载链接:Download OrbStack Fast, light, simple Docker Desktop alternative 选择是Apple M系列处理器, 或 Intel系列处理器 到这里就安装好了Orbstack软件,下面开始配置docker 下…...
【嵌入式大赛应用赛道】机械手臂
电机 进步电机:它的转动是以确定的步数进行的,只要计算好脉冲数量和频率,就可以准确预测和控制电机的转动角度、速度以及停止的位置 伺服电机:将输入的电信号(如电压或电流指令)转换成轴上的精确旋转运动…...
MES系统主要包括那些功能?
一开始接触MES系统,对MES细条的功能不清楚,这样很正常,因为MES系统相对于其他系统来讲,功能有多又复杂! 作为曾参与200企业MES系统架构的资深从业人员,我给大家选出了一款优秀模板——简道云MES系统,给大家…...
git 合并commit
操作步骤 合并commit cd xxx/ git checkout a8c0efegfwgtw # 最新commit git reset rhgertheryhg --soft # 最初的commit git status git checkout -b test1 git commit -m "test1" git branch git push origin test1 git tag test1_v0.0.1 git push origin test1_…...
【ARMv8/v9 系统寄存器 5 -- CPU ID 判断寄存器 MPIDR_EL1 使用详细介绍】
文章目录 寄存器名称: MPIDR_EL1寄存器结构:主要功能和用途亲和级别(Affinity Levels)简介CORE ID 获取函数 在ARMv8-A架构中, MPIDR_EL1寄存器是一个非常重要的系统寄存器,它提供了关于处理器在其物理和逻辑配置中的位置的信息。…...
软件工程课程设计之酒店管理系统的设计与实现
这是一个简化的酒店管理系统的需求分析文档、系统设计文档、测试文档的结构概述,以及部分实现阶段的代码示例。详细设计阶段的数据字典、ER图、模块分类图将以文字描述形式给出,而完整的代码未完全实现。这里只做软件工程部分的设计需求说明哈࿵…...
函数递归练习
目录 1.分析下面选择题 2.实现求第n个斐波那契数 3.编写一个函数实现n的k次方,使用递归实现。 4.写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和 5.递归方式实现打印一个整数的每一位 6.实现求n的阶乘 1.分析下面选择…...
公有云Linux模拟TCP三次挥手与四次握手(Wireshark抓包验证版)
目录 写在前面环境准备实验步骤1. 安装nc工具2. 使用nc打开一个连接2.1 公有云-安全组放行对应端口(可选) 3. 打开Wireshark抓包工具4. 新开终端,进行连接5. 查看抓包文件,验证TCP三次握手与四次挥手TCP三次握手数据传输TCP四次挥…...
【Day3:JAVA运算符、方法的介绍】
目录 1、运算符1.1 赋值运算符1.2 比较运算符1.3 逻辑运算符1.3.1 逻辑运算符概述1.3.2 逻辑运算符分类1.3.3 短路的逻辑运算符 1.4 三元运算符1.5 运算符优先级 2、方法2.1 方法介绍2.2 方法的定义和调用格式2.2.1 方法的调用2.2.2 带参数方法的调用2.2.3 带返回值方法的调用2…...
Chrome查看User Agent的实战教程
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
Linux 第三十四章
🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C,linux 🔥座右铭:“不要等到什么都没有了…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
