Python 如何实现职责链设计模式?什么是职责链设计模式?Python 职责链设计模式示例代码

什么是职责链(Chain of Responsibility)设计模式?

职责链(Chain of Responsibility)设计模式是一种行为型设计模式,旨在构建一个对象链,每个对象都有机会处理请求,并且可以将请求传递给链中的下一个对象。

在这里插入图片描述

在这个模式中,请求沿着链条依次传递,直到其中的某个对象处理请求为止。每个处理器(Handler)对象都包含一个指向下一个处理器的引用,形成了一个链式结构。请求进入链条的顶端,并从顶端的处理器开始处理,若顶端处理器无法处理该请求,它会将请求传递给下一个处理器,直至找到合适的处理器为止。
在这里插入图片描述
这种模式的主要目的是解耦发送者和接收者,使多个对象都有机会处理请求,而不需要明确指定请求的接收者。这样可以增强系统的灵活性,因为发送者不需要知道请求最终会由哪个对象处理,同时也可以动态地调整和扩展处理器链。

主要角色:
  1. 抽象处理者(Handler): 定义了处理请求的接口,通常包含一个指向下一个处理者的引用(后继者)。该角色提供一个处理请求的方法,通常是一个抽象方法或者是一个虚拟方法,子类需要实现该方法。抽象处理者可以决定是否将请求传递给下一个处理者。

  2. 具体处理者(ConcreteHandler): 实现了抽象处理者定义的接口,在收到请求时负责处理请求。如果能够处理请求,则直接进行处理;如果不能处理,则将请求传递给下一个处理者。

优点:
  1. 解耦发送者和接收者: 发送者无需知道请求的具体处理者,降低了发送者和接收者之间的耦合度,增强了系统的灵活性。

  2. 动态的请求处理流程: 可以动态地改变和调整处理请求的顺序和流程,增加了灵活性和可扩展性。

  3. 单一职责原则: 每个具体处理者只负责处理自己能够处理的请求,遵循了单一职责原则。

  4. 可拓展性: 可以灵活地新增、删除或调整处理者,以适应不同的业务需求。

  5. 简化了对象之间的连接: 无需发送者了解整个处理链的结构,只需要将请求发送给链条的起始处理者即可。

缺点:
  1. 请求未必被处理: 如果没有合适的处理者处理请求,可能会导致请求未被处理。

  2. 链过长可能影响性能: 如果处理链过长,可能会影响性能,因为请求需要在整个链条上进行传递和寻找处理者。


Python 职责链设计模式示例代码(一):

假设我们要实现在线支付系统中,需要根据用户的信用评级给予不同的授信额度。这个场景可以使用职责链模式来实现。

from abc import ABC, abstractmethod

# 抽象处理者
class CreditHandler(ABC):
    def __init__(self, successor=None):
        self.successor = successor

    def set_successor(self, successor):
        self.successor = successor

    @abstractmethod
    def check_credit(self, user):
        pass

# 具体处理者1 - 优秀信用用户
class ExcellentCreditHandler(CreditHandler):
    def check_credit(self, user):
        if user['credit_score'] >= 80:
            print(f"Excellent credit score for {user['name']}. Credit limit: 50000")
        elif self.successor:
            self.successor.check_credit(user)

# 具体处理者2 - 良好信用用户
class GoodCreditHandler(CreditHandler):
    def check_credit(self, user):
        if 60 <= user['credit_score'] < 80:
            print(f"Good credit score for {user['name']}. Credit limit: 20000")
        elif self.successor:
            self.successor.check_credit(user)

# 具体处理者3 - 一般信用用户
class FairCreditHandler(CreditHandler):
    def check_credit(self, user):
        if user['credit_score'] < 60:
            print(f"Fair credit score for {user['name']}. Credit limit: 10000")
        elif self.successor:
            self.successor.check_credit(user)

# 客户端代码
if __name__ == "__main__":
    # 用户信息
    user1 = {'name': '张三', 'credit_score': 85}
    user2 = {'name': '李四', 'credit_score': 70}
    user3 = {'name': '王五', 'credit_score': 50}

    # 创建处理者链
    excellent_handler = ExcellentCreditHandler()
    good_handler = GoodCreditHandler()
    fair_handler = FairCreditHandler()

    # 设置处理者顺序
    excellent_handler.set_successor(good_handler)
    good_handler.set_successor(fair_handler)

    # 发送请求
    excellent_handler.check_credit(user1)
    excellent_handler.check_credit(user2)
    excellent_handler.check_credit(user3)

这个示例模拟了一个根据用户信用评级给予不同授信额度的场景。根据用户的信用评级,不同的处理者会决定用户的授信额度,如果用户信用评级不符合任何处理者的条件,则不给予授信。


Python 职责链设计模式示例代码(二):

假设我们有一个在线购物系统,需要根据用户的会员等级给予不同的优惠。这个场景可以用职责链模式来实现。

from abc import ABC, abstractmethod

# 抽象处理者
class DiscountHandler(ABC):
    def __init__(self, successor=None):
        self.successor = successor

    def set_successor(self, successor):
        self.successor = successor

    @abstractmethod
    def apply_discount(self, user, amount):
        pass

# 具体处理者1 - VIP会员折扣
class VIPDiscountHandler(DiscountHandler):
    def apply_discount(self, user, amount):
        if user['is_vip']:
            print(f"VIP discount applied for {user['name']}. Final amount: {amount * 0.7}")
        elif self.successor:
            self.successor.apply_discount(user, amount)

# 具体处理者2 - 普通会员折扣
class RegularDiscountHandler(DiscountHandler):
    def apply_discount(self, user, amount):
        if user['is_regular']:
            print(f"Regular member discount applied for {user['name']}. Final amount: {amount * 0.9}")
        elif self.successor:
            self.successor.apply_discount(user, amount)

# 具体处理者3 - 无折扣
class NoDiscountHandler(DiscountHandler):
    def apply_discount(self, user, amount):
        print(f"No discount applied for {user['name']}. Final amount: {amount}")

# 客户端代码
if __name__ == "__main__":
    # 用户信息
    user1 = {'name': 'Alice', 'is_vip': True, 'is_regular': False}
    user2 = {'name': 'Bob', 'is_vip': False, 'is_regular': True}
    user3 = {'name': 'Eve', 'is_vip': False, 'is_regular': False}

    # 创建处理者链
    vip_handler = VIPDiscountHandler()
    regular_handler = RegularDiscountHandler()
    no_discount_handler = NoDiscountHandler()

    # 设置处理者顺序
    vip_handler.set_successor(regular_handler)
    regular_handler.set_successor(no_discount_handler)

    # 发送请求
    vip_handler.apply_discount(user1, 100)
    vip_handler.apply_discount(user2, 100)
    vip_handler.apply_discount(user3, 100)

这个示例模拟了一个用户购买商品时根据其会员等级获得不同折扣的场景。根据用户是否是 VIP 会员或普通会员,处理者会决定是否给予折扣,如果不符合条件,则没有折扣。


使用职责链设计模式时,需要注意哪些地方?

在使用职责链设计模式时,需要注意以下几个方面:

  1. 链的构建: 确保正确构建处理者链。每个处理者都应该知道其后继者是谁,以便请求可以沿着链传递。

  2. 避免循环链: 确保链不会形成循环,否则可能导致请求陷入无限循环,影响系统性能。

  3. 请求的处理: 每个处理者应该明确自己能够处理的请求类型和条件,确保不同处理者之间的处理逻辑不重叠或冲突。

  4. 适当的终止条件: 确保有适当的终止条件。如果没有一个处理者能够处理请求,需要有默认处理或者终止请求的处理方式。

  5. 灵活性与可扩展性: 职责链模式的灵活性是其优势之一,但也要确保链条的灵活性不会影响到代码的维护和扩展。

  6. 性能考虑: 过长的处理者链可能会影响性能,因为每个请求需要在整个链条上进行传递和寻找处理者。在设计时需权衡灵活性与性能。

  7. 单一职责原则: 每个处理者最好只负责一种类型的请求,遵循单一职责原则。

  8. 清晰的责任划分: 处理者的责任应该清晰,每个处理者的作用和职责应该被明确定义,以避免混乱和不必要的复杂性。

综上所述,使用职责链模式时需注意合理构建链条、避免循环、定义清晰的终止条件和责任划分,以确保系统的正确性、可维护性和扩展性。


本文就到这里了,感谢您的阅读 。别忘了点赞、收藏~ Thanks♪(・ω・)ノ 🍇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/164013.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++初阶 | [三] 类和对象(中)

摘要&#xff1a;类的6个默认成员函数&#xff0c;日期类 如果一个类中什么成员都没有&#xff0c;简称为空类。然而&#xff0c;空类并不是什么成员都没有&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成6个默认成员函数。默认成员函数&#xff1a;用户没有显式…

python中列表的基础解释

列表&#xff1a; 一种可以存放多种类型数据的数据结构 列表的创建&#xff1a; 1.用【】创建列表 #创建一个空列表 list1[] #创建一个非空列表 list2 [zhang,li,ying,1,2,3] #输出内容及类型 print(list1,type(list1)) print(list2,type(list2))结果&#xff1a; 2.使用list…

《视觉SLAM十四讲》-- 回环检测

文章目录 10 回环检测10.1 概述10.1.1 回环检测的意义10.1.2 回环检测的方法10.1.3 准确率和召回率 10.2 词袋模型10.3 字典10.3.1 字典的结构10.3.2 实践&#xff1a;创建字典 10.4 相似度计算10.4.1 理论部分10.4.2 实践&#xff1a;相似度的计算 10.5 实验分析与评述 10 回环…

股票价格预测 | Python实现基于CNN卷积神经网络的股票预测模型(keras,Conv1D)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 股票价格预测 | Python实现基于CNN卷积神经网络的股票预测模型(keras) 源码设计 import quandl import datetimedf = quandl

FreeRTOS(教程非常详细)

概述&#xff1a; 之前写了关于FreeRTOS的部分内容&#xff0c;为了方便阅读&#xff0c;现在给汇总到一起了。全部学习完后&#xff0c;恭喜你对FreeRTOS有了更深的认知。 第一章 FreeRTOS移植到STM32 第二章 FreeRTOS创建任务 第三章 FreeRTOS任务管理 第四章 FreeRTOS消…

LeetCode【12】整数转罗马数字

题目&#xff1a; 思路&#xff1a; https://blog.csdn.net/m0_71120708/article/details/128769894 代码&#xff1a; public String intToRoman(int num) {String[] thousands new String[] {"", "M", "MM", "MMM"};String[] hun…

【自然语言处理】【大模型】赋予大模型使用工具的能力:Toolformer与ART

赋予大模型使用工具的能力&#xff1a;Toolformer与ART ​ 本文介绍两种赋予大模型使用外部工具能力的方法&#xff1a;Toolformer和ART。 Toolformer论文地址&#xff1a;https://arxiv.org/pdf/2302.04761.pdf ART论文地址&#xff1a;https://arxiv.org/pdf/2303.09014.pd…

【网络奇遇记】那年我与计算机网络的浅相知

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. 计算机网络的定义1.1 计算机早期的一个最简单的定义1.2 现阶段计算机网络的一个较好的定义 二. …

【IPC】消息队列

1、IPC对象 除了最原始的进程间通信方式信号、无名管道和有名管道外&#xff0c;还有三种进程间通信方式&#xff0c;这 三种方式称之为IPC对象 IPC对象分类&#xff1a;消息队列、共享内存、信号量(信号灯集) IPC对象也是在内核空间开辟区域&#xff0c;每一种IPC对象创建好…

【汇编】处理字符问题

文章目录 前言一、处理字符问题1.1 汇编语言如何处理字符1.2 asciiascii码是什么&#xff1f;ascii码表是什么&#xff1f; 1.3 汇编语言字符示例代码 二、大小写转换2.1 问题&#xff1a;对datasg中的字符串2.2 逻辑与和逻辑或2.3 程序&#xff1a;解决大小写转换的问题一个新…

「项目阅读系列」go-gin-example star 6.5k!(1)

文章目录 准备工作适宜人群项目信息 项目结构代码阅读主要模块代码主函数模块router 路由模块auth 授权模块数据库 修改文章请求分析其他依赖 总结 准备工作 适宜人群 初学 go 语法&#xff0c;希望了解 go 项目的构建过程和方式。 项目信息 go-gin-example 项目是使用 gin…

qt-C++笔记之两个窗口ui的交互

qt-C笔记之两个窗口ui的交互 code review! 文章目录 qt-C笔记之两个窗口ui的交互0.运行1.文件结构2.先创建widget项目&#xff0c;搞一个窗口ui出来3.项目添加第二个widget窗口出来4.补充代码4.1.qt_widget_interaction.pro4.2.main.cpp4.3.widget.h4.4.widget.cpp4.5.second…

JAVA for 循环训练 Pattern

import java.util.Scanner;public class Pattern {public static void main(String[] args) {int[] arr {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0};Scanner in new Scanner(System.in);System.out.print("请输入n:");int n in.nextInt();in.close();for …

LeetCode27.移除元素(暴力法、快慢指针法)

每日一题&#xff1a;LeetCode27.移除元素 1.问题描述2.解题思路3.代码 1.问题描述 问题描述&#xff1a;给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。不要使用额外的数组空间&#xff0c;你必…

Linux(Ubuntu)安装JDK环境

系统环境 Ubuntu20.04 下载JDK压缩包 前往Oracle官网进行后续下载或单击下载JDK压缩包 下拉找到JDK8&#xff0c;在Linux板块下选择适配系统架构的压缩包文件(后缀为tar.gz)&#xff0c;系统架构可通过uname -m命令查看 安装JDK 安装环境通常放在/usr/local下&#xff0c;进入…

免费稳定几乎无门槛,我的ChartGPT助手免费分享给你

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享。 概述 ChatGPT想必大家应该都不陌生了&#xff0c;大部分人或多或少都接触了&#xff0c;好多应该都是通过openAi的官方进行使用的&#xff0c;这个门槛对大部分人有点高&#xff0c;…

公共字段自动填充-@TableField的fill实现(2)

TheadLocal 客户端发送的每次http请求&#xff0c;在服务端都会分配新的线程。因此登录检查过滤器、controller、元数据对象处理器属于一个线程。 TheadLocal是线程的局部变量&#xff1a; TheadLocal常用方法&#xff1a; 如何在元数据对象处理器中获取当前登录用户的id&…

开发知识点-uniapp微信小程序-开发指南

uniapp uni.chooseLocationgetCurrentPages美团外卖微信小程序开发uniapp-美团外卖微信小程序开发P1 成果展示P2外卖小程序后端&#xff0c;学习给小程序写http接口P3 主界面配置P4 首页组件拆分P13 外卖列表布局筛选组件商家 布局测试数据创建样式 请求商家外卖数据封装请求并…

酷柚易汛ERP - 序列号盘点操作指南

1、应用场景 将系统中开启序列号的商品数量与与实际存放的数量进行对比。 2、主要操作 2.1 录入序列号 打开【盘点】-【序列号盘点】&#xff0c;新增序列号盘点单&#xff0c;点击【SN】按钮&#xff0c;在弹框中输入序列号。 支持扫描枪录入序列号支持复制粘贴序列号录入…

JS特效:跟随鼠标移动的小飞机

前端网页中&#xff0c;用JS实现鼠标移动时&#xff0c;页面中的小飞机向着鼠标移动。 效果 源码 <!DOCTYPE html> <html><head><style>*{margin: 0;padding: 0;}body{height: 100vh;background: linear-gradient(200deg,#005bea,#00c6fb);}#plane{…