当前位置: 首页 > news >正文

【八】python装饰器模式

文章目录

  • 8.1 装饰器模式简介
  • 8.2 装饰器模式作用
  • 8.3 装饰器模式构成
    • 8.3.1 装饰器模式包含以下几个核心角色:
    • 8.3.2 UML类图
  • 8.4 装饰器模式python代码实现
    • 8.4.1 基本装饰器的使用
    • 8.4.2 多个装饰器的执行顺序
    • 8.4.3 带返回值的装饰器的使用
    • 8.4.4 装饰器模式-关联类模式
    • 8.4.5 装饰器模式-无参数
    • 8.4.6 装饰器模式-接收原函数参数
    • 8.4.7 装饰器模式-装饰器自带函数
    • 8.4.8 装饰器模式应用-事务提交与回滚
  • 8.5 装饰器模式优点与缺点

8.1 装饰器模式简介

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

8.2 装饰器模式作用

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
主要解决的问题:主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

8.3 装饰器模式构成

8.3.1 装饰器模式包含以下几个核心角色:

  • 抽象组件(Component):定义了原始对象和装饰器对象的公共接口或抽象类,可以是具体组件类的父类或接口。
  • 具体组件(Concrete Component):是被装饰的原始对象,它定义了需要添加新功能的对象。
  • 抽象装饰器(Decorator):继承自抽象组件,它包含了一个抽象组件对象,并定义了与抽象组件相同的接口,同时可以通过组合方式持有其他装饰器对象。
  • 具体装饰器(Concrete Decorator):实现了抽象装饰器的接口,负责向抽象组件添加新的功能。具体装饰器通常会在调用原始对象的方法之前或之后执行自己的操作。
    装饰器模式通过嵌套包装多个装饰器对象,可以实现多层次的功能增强。每个具体装饰器类都可以选择性地增加新的功能,同时保持对象接口的一致性。

8.3.2 UML类图

在这里插入图片描述

8.4 装饰器模式python代码实现

8.4.1 基本装饰器的使用

import time#装饰器函数
def cont_time(func):def inner():start_time = time.time()print("计时开始")func()end_time = time.time()print('计时结束,耗时{:.2f}秒'.format(end_time-start_time))return inner#功能函数
@cont_time # 相当于do_work = cont_time(do_work)
def do_work():print('do work开始')time.sleep(1)print('do work结束')return 'work is done'res = do_work()
print(res)"""结果如下:
计时开始
do work开始
do work结束
计时结束,耗时1.01秒
None
"""

8.4.2 多个装饰器的执行顺序

def decorator1(func):print("执行装饰器1")def wrapper():print("在装饰器1中执行前")func()print("在装饰器1中执行后")return wrapper
def decorator2(func):print("执行装饰器2")def wrapper():print("在装饰器2中执行前")func()print("在装饰器2中执行后")return wrapper
@decorator1
@decorator2
def my_function():print("函数执行")my_function()

8.4.3 带返回值的装饰器的使用

import time#装饰器函数
def cont_time(func):def inner():start_time = time.time()print("计时开始")res = func()  #在这里接收end_time = time.time()print('计时结束,耗时{:.2f}秒'.format(end_time-start_time))return resreturn inner#功能函数
@cont_time # 相当于do_work = cont_time(do_work)
def do_work():print('do work开始')time.sleep(1)print('do work结束')return 'work is done'res = do_work()
print(res)"""结果如下:
计时开始
do work开始
do work结束
计时结束,耗时1.01秒
None
"""

8.4.4 装饰器模式-关联类模式

# encoding: utf-8"""
装饰模式包含以下4个角色: Component(抽象构件) ConcreteComponent(具体构件)Decorator(抽象装饰类) ConcreteDecorator(具体装饰类)"""
# 抽象构建,原有产品的功能抽象
class Component(object):def operation(self):raise NotImplementedError#具体构件,就是被装饰的类,继承抽象组件
class ConcreteComponent(Component):def operation(self):print('车在地上跑')#抽象装饰类,和被装饰的类共同继承抽象组件,在这里重写抽象类中的方法,改变被装饰类的行为
class Decorator(Component):def __init__(self):self._component = Nonedef set_component(self,component):self._component = componentdef operation(self):if self._component is not None:self._component.operation()#具体装饰类A,给汽车扩展一个水里跑的功能
class ConcreteDecoratorA(Decorator):def __init__(self):super(ConcreteDecoratorA,self).__init__()def operation(self):super(ConcreteDecoratorA,self).operation()print('车在水里跑')
# 具体装饰类B
class ConcreteDecoratorB(Decorator):def operation(self):super(ConcreteDecoratorB,self).operation()self._add_behavior()# print('具体装饰对象B的操作')def _add_behavior(self):print('车在天上跑')if __name__ == '__main__':# 原有的汽车功能,只能地上跑c = ConcreteComponent()#被A装饰器装饰后,扩展水里跑的功能d1 = ConcreteDecoratorA()# 继续被B装饰器装饰后,扩展天上跑功能d2 = ConcreteDecoratorB()d1.set_component(c)d2.set_component(d1)d2.operation()

8.4.5 装饰器模式-无参数

# 装饰器--无参数
import time# 装饰器,记录函数运行时间
def decorator01(fun):def wapper():print('装饰器开始运行')stime = time.time()print('开始运行原函数')fun()etime = time.time()print('原函数结束')print("原函数运行时间: {TIME}".format(TIME=etime - stime))print('装饰器结束')return wapper  # 必须要返回一个函数的内存地址# 使用装饰器装饰某个函数,等价于 test01=decorator01(test01),
# 即将test01实际引用变成wapper函数内存地址,所以执行test01实际是执行wapper
@decorator01
def test01():time.sleep(2)print("test01 运行")test01()  # 不修改代码和调用方式,实现添加记录时间功能

8.4.6 装饰器模式-接收原函数参数


# 装饰器2-带参数
import time# 装饰器,记录函数运行时间
def decorator01(fun):def wapper(*args, **kwargs):  # 使用非固定参数,无论参数是什么,都可以传递进来stime = time.time()fun(*args, **kwargs)etime = time.time()print("fun run time is {TIME}".format(TIME=etime - stime))return wapper  # 必须要返回一个函数的内存地址# test01() = wapper(), 所以装饰器加参数是给嵌套函数加参数
@decorator01
def test01(args1):time.sleep(2)print("参数是 {NAME} ".format(NAME=args1))test01("参数示例")  # 不修改代码和调用方式,实现添加记录时间功能

8.4.7 装饰器模式-装饰器自带函数

# 装饰器
import time# 如果装饰器有参数,最外层是装饰器的参数
def decorator01(*args, **kwargs):print("装饰器参数:", *args, **kwargs)def out(fun):  # 第二层才是接受的函数def wapper(*args, **kwargs):  # 使用非固定参数,无论参数是什么,都可以传递进来stime = time.time()fun(*args, **kwargs)etime = time.time()print("fun run time is {TIME}".format(TIME=etime - stime))return wapper  # 必须要返回一个函数的内存地址return out  # 要返回装饰函数的内存地址# 装饰器本身带参数,此时 decorator01(arg)=out,即相当于 @out装饰test01,所以 test01=out(fun)=wapper
@decorator01(5)
def test01(args1):time.sleep(2)print("参数是 {NAME} ".format(NAME=args1))test01("参数示例")  # 不修改代码和调用方式,实现添加记录时间功能

8.4.8 装饰器模式应用-事务提交与回滚

在事务处理中,装饰器模式可以用于在执行数据库操作之前和之后执行一些附加的操作,例如日志记录、验证、事务管理等。下面是一个使用装饰器模式实现事务处理的示例:

class DatabaseOperation:  """假设我们有一个数据库操作类 DatabaseOperation,它执行数据库的增、删、改、查操作。我们希望在执行这些操作时,先进行事务的开启,在操作完成后进行事务的提交或回滚。"""def __init__(self, operation):  self.operation = operation  def execute(self):  try:  # 开始事务  self.start_transaction()  # 执行数据库操作  self.operation.execute()  # 提交事务  self.commit_transaction()  except Exception as e:  # 发生异常时回滚事务  self.rollback_transaction()  def start_transaction(self):  # 实现事务开始的逻辑  pass  def commit_transaction(self):  # 实现事务提交的逻辑  pass  def rollback_transaction(self):  # 实现事务回滚的逻辑  passclass TransactionDecorator: """定义一个装饰器 TransactionDecorator,它接受一个数据库操作对象,并返回一个添加了事务处理逻辑的装饰器对象。"""    def __init__(self, operation):  self.operation = operation  def execute(self):  transaction = TransactionDecorator()  transaction.start_transaction()  try:  self.operation.execute()  transaction.commit_transaction()  except Exception as e:  transaction.rollback_transaction()#使用装饰器模式来执行带有事务处理的操作
@TransactionDecorator  
class MyDatabaseOperation(DatabaseOperation):  def __init__(self, operation):  super().__init__(operation)

8.5 装饰器模式优点与缺点

  • 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
  • 缺点:多层装饰比较复杂。

相关文章:

【八】python装饰器模式

文章目录 8.1 装饰器模式简介8.2 装饰器模式作用8.3 装饰器模式构成8.3.1 装饰器模式包含以下几个核心角色:8.3.2 UML类图 8.4 装饰器模式python代码实现8.4.1 基本装饰器的使用8.4.2 多个装饰器的执行顺序8.4.3 带返回值的装饰器的使用8.4.4 装饰器模式-关联类模式…...

Unity-小工具-LookAt

Unity-小工具-LookAt 🥙介绍 🥙介绍 💡通过扩展方法调用 gameObject.LookAtTarget,让物体转向目标位置 💡gameObject.StopLookat 停止更新 💡可以在调用时传入自动停止标记,等转向目标位置后自…...

TCP实现一对一聊天

一,创建类 二,类 1.ChatSocketServer类 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Sca…...

全面高压化与全面超快充,破解新能源汽车的时代难题

是什么让新能源车主感到疲惫与焦虑?是什么阻挡更多消费者选择新能源汽车?我们在身边进行一个简单的调查就会发现,问题的答案非常一致:充电。 充电难,充电慢的难题,始终是困扰新能源汽车产业发展&#xff0c…...

02 CSS基础入门

文章目录 一、CSS介绍1. 简介2. 相关网站3. HTML引入方式 二、选择器1. 标签选择器2. 类选择器3. ID选择器4. 群组选择器 四、样式1. 字体样式2. 文本样式3. 边框样式4. 表格样式 五、模型和布局1. 盒子模型2. 网页布局 一、CSS介绍 1. 简介 CSS主要用于控制网页的外观&#…...

MyBatis框架中的5种设计模式总结

前言 MyBatis框架中使用的5种设计模式分别是:1、建造者模式(生成器模式)。2、工厂模式。3、单例模式。4、代理模式。5、适配器模式。 1、建造者模式(生成器模式) 在MyBatis环境的初始化过程中,SqlSessio…...

ffmpeg相关命令

视频转码 dav转化为mp4格式 ffmpeg -i 2021-08-10.dav -codec copy 11.mp4二进制文件转为mp4格式 // -c:v 指定视频流编码器,不指定编码会默认用mp4这种容器的默认音视频编码进入编码 // copy:不重新编码直接copy源视频流ffmpeg -i 1701687125-4fc72a…...

锂电3V升12V1A升压芯片WT3209

锂电3V升12V1A升压芯片WT3209 WT3209是一款高功率密度全集成BOOST升压转换器,具备高效能解决方案。3V升12V1A,5V升12V1A WT3209内部集成的功率MOSFET管导通电阻为上管13mΩ和下管11mΩ,具备2A开关电流能力,并且能够提供高达12.6V的输出电压。…...

Unity 置顶OpenFileDialog文件选择框

置顶文件选择框 🌭处理前🥙处理后 🌭处理前 🥙处理后 解决方案...

oomall课堂笔记

一、项目分层结构介绍 controller层(控制器层): 作用:负责输出和输入,接收前端数据,把结果返回给前端。 1.处理用户请求,接收用户参数 2.调用service层处理业务,返回响应 servi…...

Qt6.5类库实例大全:QFrame

哈喽大家好,我是20YC小二!欢迎扫码关注公众号,现在可免费领取《C程序员》在线视频教程哦! ~下面开始今天的分享内容~ 1. QFrame介绍 QFrame是Qt框架中的一个框架控件类,主要用于在图形用户界面(GUI)中创建框架&#…...

Java 数据结构篇-用数组、堆实现优先级队列

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 优先级队列说明 2.0 用数组实现优先级队列 3.0 无序数组实现优先级队列 3.1 无序数组实现优先级队列 - 入队列 offer(E value) 3.2 无序数组实现优先级队列 - 出…...

Reactor模型

目录 1.Reactor模型是什么2.Reactor 模型应用场景3.使用 Reactor 模型的软件4.Reactor 模型 与 Actor 模型 的关系 本文主要介绍Reactor模型基本概念以及应用场景。 1.Reactor模型是什么 Reactor模型是一种事件驱动的设计模式,用于处理服务请求,它是由…...

【SpringCloud】通过Redis手动更新Ribbon缓存来解决Eureka微服务架构中服务下线感知的问题

文章目录 前言1.第一次尝试1.1服务被调用方更新1.2压测第一次尝试1.3 问题分析1.4 同步的不是最新列表 2.第二次尝试2.1调用方过滤下线服务2.2压测第二次尝试2.3优化 写到最后 前言 在上文的基础上,通过压测的结果可以看出,使用DiscoveryManager下线服务…...

如何做好性能压测?压测环境设计和搭建的7个步骤你知道吗?

简介:一般来说,保证执行性能压测的环境和生产环境高度一致是执行一次有效性能压测的首要原则。有时候,即便是压测环境和生产环境有很细微的差别,都有可能导致整个压测活动评测出来的结果不准确。 1. 性能环境要考虑的要素 1.1 系…...

Qt12.13

...

目标检测YOLO系列从入门到精通技术详解100篇-【目标检测】SLAM(基础篇)(五)

目录 前言 几个相关概念 双目视惯雷达SLAM 相关工作 系统综述 视觉前端...

鸿蒙开发之页面与组件生命周期

一、页面间的跳转 创建文件的时候记得选择创建page文件,这样就可以在main->resources->profile->main_pages.json中自动形成页面对应的路由了。如果创建的时候你选择了ArkTS文件,那么需要手动修改main_pages.json文件中,添加相应的…...

Kotlin开发之低功耗蓝牙(引用三方库)的详解一

在我们工作中,如果涉及到软硬结合,经常会用到蓝牙,而蓝牙有两种:一种是普通的蓝牙,一种是低功耗的蓝牙,今天我们主要讲解的是低功耗蓝牙:主要根据第三方库进行的讲解 第一步:在使用…...

5G/4G工业DTU扬尘在线监测:解决工地扬尘困扰的最佳方案

在如今快速发展的工业环境中,扬尘污染成为了一个严重的问题。工地扬尘不仅对环境造成污染,还对工作人员的健康产生负面影响。为了解决这一问题,5G/4G工业DTU扬尘在线监测应运而生。 5G/4G工业DTU扬尘在线监测原理 5G/4G工业DTU扬尘在线监测是…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...

人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型

在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...

第八部分:阶段项目 6:构建 React 前端应用

现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...