【八】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.mzph.cn/news/218674.shtml

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

相关文章

排序算法---希尔排序

1. 基本思想 希尔排序是插入排序的一种,它与直接插入排序不同的是,它会优先比较距离较远的元素,因此希尔排序又被称为“缩小增量排序”。希尔排序的实现思路是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序&…

​flutter 代码混淆

Flutter 应用混淆:Flutter 应用的混淆非常简单,只需要在构建 release 版应用时结合使用 --obfuscate 和 --split-debug-info 这两个参数即可。–obfuscate --split-debug-info 用来指定输出调试文件的位置,该命令会生成一个符号映射表。目前支…

智能驾驶时代加速到来,爱芯元智成车载芯片界最大黑马?

今年以来,随着新能源汽车厂商们轰轰烈烈的“开城之战”持续上演,国内新能源汽车行业俨然已进入智能驾驶时代。在这场技术革新大潮中,扮演重要角色的除了处于视觉中心风光无两的车企,还有上游诸多的智能驾驶方案供应商。 下游的军…

MS913/914 25-100MHz 10/12 位用于平面显示器链路Ⅲ的具有直流平衡编码和双向控制通道的串化器和解串器

MS913/MS914 芯片组是 25MHz~100MHz 10 位/12 位 FPD Link III SER/DES(串化器/解串器),它提供高速 FPD-Link III 接口和高速正向通路以及用于差分对上数据发送的双向 控制通路。广泛应用于车载摄像,医疗设备,管道探测等领 域。 主要特点…

lwIP 细节之六:connected、sent、poll 回调函数是何时调用的

使用 lwIP 协议栈进行 TCP 裸机编程,其本质就是编写协议栈指定的各种回调函数。将你的应用逻辑封装成函数,注册到协议栈,在适当的时候,由协议栈自动调用,所以称为回调。 注:除非特别说明,以下内…

HarmonyOS4.0从零开始的开发教程11Video组件的使用

HarmonyOS(九)Video组件的使用 概述 在手机、平板或是智慧屏这些终端设备上,媒体功能可以算作是我们最常用的场景之一。无论是实现音频的播放、录制、采集,还是视频的播放、切换、循环,亦或是相机的预览、拍照等功能…

Python码上行动系列丛书(由北京大学出版社出版)

前言 Python码上行动系列丛书火热来袭💥💥💥 三册在手,Python全掌握!无论是初学者还是进阶玩家,我们都有你想要的! 让ChatGPT带你轻松入门Python编程,享受编程带来的乐趣&#xff0…

【数据结构】——二叉树功能

前言:我们前面已经了解了二叉树的一些概念,那么我们今天就来了解下二叉树的遍历实现和一些性质。 二叉树的遍历方式有三种:前序,中序,后序。 前序:先根节点,再左子树,最后右子树。 中…

Linux——MySQL数据库系统()

一、访问MySQL数据库 MySQL数据库系统也是一个典型的C/S(客户端/服务器)架构的应用,要访问MySQL数据库需要使用专门的客户端软件。在Linux系统中,最简单、易用的MySQL客户端软件是其自带的mysql命令工具。 1、登录到MySQL服务器经过安装后的初…

Leetcode—783.二叉搜索树节点最小距离【简单】

2023每日刷题(五十八) Leetcode—783.二叉搜索树节点最小距离 实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ void dfs(struct TreeNode* roo…

在接触新的游戏引擎的时候,如何能快速地熟悉并开发出一款新游戏?

引言 大家好,今天分享点个人经验。 有一定编程经验或者游戏开发经验的小伙伴,在接触新的游戏引擎的时候,如何能快速地熟悉并开发出一款新游戏? 利用现成开发框架。 1.什么是开发框架? 开发框架,顾名思…

ROS2 学习08 导航Nav2:简介、安装、测试效果、错误处理

1、简介 在ROS2中自动导航使用Nav2来实现。 Nav2 使用几个独立的模块化服务,通过 ROS 2接口(例如动作服务器或服务)与行为树 (BT) 通信。 Nav2 输入包括:TF转换、一个地图源、一个行为树 (BT) XML 文件和相关的传感器数据源; Nav…

C语言好题分享七(三数之和)

❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载,请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤ 三数之和 题目来源LeetCode:刷题传送门 题目:给你一个整数数组 nums ,判断…

EasyRecovery2024专业版下载安装步骤图文详细教程

EasyRecovery是一款操作安全、价格便宜、用户自主操作的非破坏性的只读应用程序,它不会往源驱上写任何东西,也不会对源驱做任何改变。它支持从各种各样的存储介质恢复删除或者丢失的文件,其支持的媒体介质包括:硬盘驱动器、光驱、…

2-分布式存储之glusterfs

任务背景 实现了远程的存储共享(NAS或SAN)后, 公司业务发展迅速, 存储空间还需要增大。使用NAS或SAN都不方便扩容,NAS可以增加新的挂载目录, SAN可以增加新的硬盘,但我们希望直接在原来挂载的业务目录上实现在线扩容,数据体量越来越大, 这个…

ChatGLM3-6B和langchain知识库阿里云部署

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、ChatGLM3-6B部署搭建环境部署GLM3 二、Chatglm2-6blangchain部署本地知识库三、Tips四、总结 前言 提示:这里可以添加本文要记录的大概内容&am…

被央视报道过的AIGC产品-贝塔创作(BetaCreator)使用指南

产品地址:betacreator.com 真人图 人台图 商品图 商品变色 建议使用浅色服装进行变色,效果更好 如果没有浅色服装,可以先把服装颜色变为白色

视频剪辑必备的6个免费素材网站

视频剪辑需要用到很多音效、视频、图片等素材,下面我就分享几个剪辑必备的免费视频素材网站,赶紧收藏起来~ 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYwNDUx 菜鸟图库虽然是个设计素材网站,但除了设计类素材之外还有很多视频、…

python学习:浅拷贝与深拷贝详解

copy 一、 & is二、浅拷贝 & 深拷贝(一)、浅拷贝(二)、深拷贝 三、问题 一、’ ’ & ‘is’ ’ 和is是python对象比较常用的两种方式,简单来说,‘ ‘操作符比较对象之间的值是否相等,如 a b 而’is’操作符比较的是对象的身份标识是否相等,即它们是否是同一个…

Linux系统解决“Key was rejected by service”

Linux系统下加载驱动模块出现如上错误提示的原因为:此驱动未经过签名。 方法一、关闭Secure Boot 如果是物理机,需要开机进入BIOS,找到“Secure Boot”的选项,然后关闭。 如果是虚拟机,可以打开虚拟设置&#xff0c…