【八】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 装饰器模式优点与缺点

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5V低压步进电机驱动芯片GC6150,应用于摄像机,机器人 医疗器械等产品中。具有低噪声、低振动的特点

GC6150是双通道5V低压步进电机驱动器,具有低噪声、低振动的特点,特别适用于相机变焦对焦系统、万向架、摇头机等精度、低噪声STM控制系统,该芯片为每个通道集成了一个256微步的驱动器。通过SPI & T2C接口,客户可以方使地调整驱…

OneNote for Windows10 彻底删除笔记本

找了超多方法,都没有用,我的OneNote都没有文件选项,要在OneDrive中删除,但是一直登不进,然后又找到一个方法: 在网页中打开Office的控制面板 "Sign in to your Microsoft account" 在“最近”一…

共筑首都绿色美好出行!苏州金龙再向北京交付33辆纯电动旅游大巴

应时而动,创新求变,方能始终屹立于市场。2023年,随着旅游市场的复苏,北京市旅游消费潜力进一步释放,客运需求量快速增长,与此同时绿色、高端、个性化旅游客车也成为市场趋势。 11月底,33辆苏州…

STM32单片机项目实例:基于TouchGFX的智能手表设计(4)LPBAM的应用

STM32单片机项目实例:基于TouchGFX的智能手表设计(4)LPBAM的应用 目录 一、概述 二、LPBAM简介 2.1 支持 LPBAM 的外设 三、LPBAM硬件机制 3.1 电源和时钟架构 3.2 速度限制 3.3 LPGPIO_IOToggle实验 一、概述 STM32U5 系列微控制器基…

uniapp实战 —— 可滚动区域 scroll-view (自适配高度,下拉刷新)

自适配高度 自定义的顶部导航栏,可参考博文 https://blog.csdn.net/weixin_41192489/article/details/134852124 如图可见,在页面滚动过程中,顶部导航栏和底栏未动,仅中间的内容区域可滚动。 整个页面的高度设置为 100%&#xf…

Java最全面试题专题---2、Java集合容器(1)

集合容器概述 什么是集合 **集合框架:**用于存储数据的容器。 集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。 任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。 **接口:**表示集合的抽象数据类…

HCIA-H12-811题目解析(3)

1、【单选题】 以下关于路由器的描述,说法错误的是? 2、【单选题】某网络工程师在输入命令行时提示如下信息:Error:Unrecognized command foun at position.对于该提示信息说法正确的是? 3、【单选题】如下图所示的网络&#xf…

Vue--第八天

Vue3 1.优点&#xff1a; 2.创建&#xff1a; 3.文件&#xff1a; 换运行插件&#xff1a; 4.运行&#xff1a; setup函数&#xff1a; setup函数中获取不到this&#xff08;this 在定义的时候是Undefined) reactive()和ref(): 代码&#xff1a; <script setup> // …

yolov8+tensorRT加速推理+部署-姿态识别-实力分割-目标检测

入门指南 这个项目演示了如何使用 TensorRT C++ API 运行 YoloV8 的 GPU 推理。它使用了我的另一个项目 tensorrt-cpp-api 在后台运行推理,因此请确保您熟悉该项目。 先决条件 在 Ubuntu 20.04 上测试并工作安装 CUDA,说明在这里。 推荐 >= 11.8安装 cuDNN,说明在这里。…

满载re:Invent 2023全新发布惊喜,亚马逊云科技下一站GenAI@巡演来啦

无限构建&#xff0c;成为生成式AI原生开发者前沿生成式AI技术之旅正式启程&#xff0c;穿越多个中国的城市&#xff0c;开发者一站式体验&#xff0c;满载re:Invent 2023全新发布惊喜。 LET’S Demo 「构」硬核 生成式AI时代的开发新范式 Amazon Q 全新的企业级生成式AI助手…

每日一练2023.12.9—— 矩阵A乘以B【PTA】

题目链接&#xff1a;L1-048 矩阵A乘以B 题目要求&#xff1a; 给定两个矩阵A和B&#xff0c;要求你计算它们的乘积矩阵AB。需要注意的是&#xff0c;只有规模匹配的矩阵才可以相乘。即若A有Ra​行、Ca​列&#xff0c;B有Rb​行、Cb​列&#xff0c;则只有Ca​与Rb​相等时&a…

Leetcode 131 分割回文串

题意理解&#xff1a; 分割回文子串&#xff0c;可以看作是划分连续的字幕组合——所以也可以用回溯的方法来解决 每个位置选与不选——该位置切割|不切割 对于每一段子串——>判断是否是回文串&#xff1a; 是&#xff1a; 继续切割 不是&#xff1a; 剪枝 解题方法…