【八】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,一经查实,立即删除!

相关文章

深度学习——第3章 Python程序设计语言(3.5 Python类和对象)

3.5 Python类和对象 目录 1. 面向对象的基本概念 2. 类和对象的关系 3. 类的声明 4. 对象的创建和使用 5. 类对象属性 6. 类对象方法 7. 面向对象的三个基本特征 8. 综合案例:汉诺塔图形化移动 1.1 面向对象的基本概念 1.1.1 对象(object&#x…

MySQL数据库,约束

关于约束 数据完整性是指数据的精确性和可靠性。防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或无效信息。 SQL规范以约束的方式对表数据进行额外的条件限制。 约束是表级的强制规定。可以在创建表时规定约束,或者在表创建之后通…

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

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

排序算法---希尔排序

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

​flutter 代码混淆

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

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

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

C 语言USB通信之使用 libusb库

在C语言中,要与USB接口通信,通常需要使用特定的库和API。以下是一些常见的库和API,用于在C语言中与USB接口通信: libusb:这是一个开源的USB库,提供了跨平台的USB设备访问功能。它提供了API,使您…

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

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

master分支切换到release分支

commit master分支的代码 glol 查看当前分支的commit id git checkout 2023.12_rel gl git checkout -b 分支名 gcp commit_id(glol) git push --set-upstream origin 分支名

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

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

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

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

OpenCloud os 9上面安装docker docker-compose脚本

#!/bin/bash #opencloudOs上面安装docker docker-compose环境 curl -o /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sed -i s/\$releasever/8/g /etc/yum.repos.d/docker-ce.repo wget https://vault.centos.org/ce…

C++异步网络库workflow入门教程(1)HTTP任务

如果觉得小弟写的可以,请给一个点赞关注支持 workFlow c异步网络库编译教程与简介 创建并启动http任务 示例 #include <workflow/WFFacilities.h> int main(){WFHttpTask * httpTask WFTaskFactory::create_http_task("http://baidu.com",0,0,0);protocol:…

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

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

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

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

Linux——MySQL数据库系统()

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

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

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

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

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

微信抖音快手QQ小程序 - 预支付接口参数out_trade_no长度限制 - jsapi统一下单接口

报错 微信小程序&#xff1a; {"code":0,"show":1,"msg":"输入源“/body/xml/out_trade_no”映射到值字段“商户订单号”字符串规则校验失败&#xff0c;字节数 35&#xff0c;大于最大值 32","data":{"from":&q…

【goland如果使用xorm执行mysql的存储过程】

goland如果使用xorm执行mysql的存储过程 需求背景 存在用户表和用户邀请关系表&#xff0c;当用户A邀请用户B&#xff0c;则B用户为A用户直接邀请的人&#xff1b;B用户邀请了C用户&#xff0c;则C用户就是A用户的间接邀请人。 如何查询当前用户间接邀请的注册用户有那些&am…