【八】python装饰器模式

news2025/2/21 23:43:06

文章目录

  • 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 res
    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.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 = None

    def set_component(self,component):
        self._component = component
    def 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):  
        # 实现事务回滚的逻辑  
        pass

    
class 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.coloradmin.cn/o/1306295.html

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

相关文章

(第67天)RMAN Duplicate 克隆 PDB

介绍 在之前 NONCDB 版本我们经常使用 RMAN Duplicate 方式来在线搭建 DataGuard,非常方便快捷。从 12C 开始 Oracle 推出了 CDB 架构后,自然也就支持使用 Duplicate 的方式来复制 CDB,但是 12C 时还没有那么智能。 从 18C 开始进行了升级,可以支持使用 RMAN Duplicate 方…

Axure的元件库的使用以及详细案例

目录 元件库的使用 元件介绍 元件的基本使用 矩形、按钮、标题的使用​编辑 图片的使用 图片以及热区的使用 表单元件的使用 表格元件的使用 登录界面 个人简介界面 元件库的使用 元件介绍 Axure提供了一套丰富的元件库,用于快速创建原型中常见的UI界面元素…

geemap学习笔记025:为地图中的底图数据添加颜色条(colorbar)

前言 为地图中的数据添加颜色条,有利于辅助地图的使用,本节就介绍一下如何在底图数据中添加颜色条。 1 导入库并显示地图 import ee import geemapee.Initialize() Map geemap.Map() Map2 添加普通颜色条以及分类颜色条 Map geemap.Map()dem ee.I…

深度学习中的各类评价指标

深度学习中的各类评价指标 1 Dice Loss2 Precision(精度)3 Recall(召回率)4 F-Score5 mAP 1 Dice Loss Dice Loss,也叫Soft Dice Coefficient,是一种用于图像分割任务的损失函数。它基于目标分割图像与模型…

希亦|鲸立|小吉内衣洗衣机好用吗?强势PK“洗护一体”王者!

随着人们的生活水平的提升,越来越多小伙伴来开始追求更高的生活水平,一些智能化的小家电就被发明出来,而且内衣洗衣机是其中一个。我们对内衣裤的清洗频次会高于普通衣服,大多数人会选择手洗内衣裤,都在手洗过程不仅会…

用户管理第2节课 -- idea 2023.2 创建表

一、懂得 1.1编码格式是防止乱码的,utf-8是完全够的,那几个基本没差别 网址: 【IDEA——连接MySQL数据库,创建库和表】_idea中数据库-CSDN博客 这些是MySQL数据库中的一些术语,可以简单解释如下: 1、col…

DICOM 文件中,VR,VL,SQ,图像二进制的几个注意点

DICOM 文件的结构,在网上有很多的学习资料,这里只介绍些容易混淆的概念,作为回看笔记。 1. 传输语法 每个传输语法,起都是表达的三个概念:大小端、显隐式、压缩算法 DICOM Implicit VR Little Endian: 1.2.840.1000…

现代岩土工程监测的利器:振弦采集仪

现代岩土工程监测的利器:振弦采集仪 振弦采集仪是一种用于工程监测的先进仪器,主要用于测量结构体的振动和应力变形情况。它采用振动传感器和数据采集系统相结合的方式,可以实时监测和记录结构体的振动频率、振幅、振动模态等参数&#xff0…

Linux----内核及发行版

1. Linux内核 Linux内核是操作系统内部操作和控制硬件设备的核心程序,它是由芬兰人林纳斯开发的。 内核效果图: 说明: 真正操作和控制硬件是由内核来完成的,操作系统是基于内核开发出来的。 2. Linux发行版 是Linux内核与各种常用软件的组合产品&am…

智能优化算法应用:基于水循环算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于水循环算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于水循环算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.水循环算法4.实验参数设定5.算法结果6.参考文…

【Proteus仿真】【51单片机】定时智能插座开关

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器,使LCD1602液晶,DS18B20温度传感器、按键、蜂鸣器、继电器开关、HC05蓝牙模块等。 主要功能: 系统运行后,LCD1602显示…

内网服务器部署maven私服简记

前言 很多企业希望创建自己的maven私服,但服务器无法和外网连通,所以这里介绍一套完整的内网部署nexus的解决方案。实现的方式也很简单,将下载好的nexus安装和项目所需的依赖仓库都上传到服务i去上去,通过脚本的方式实现批量导入…

【Spark精讲】Spark任务运行流程

Spark任务执行流程 部署模式是根据Drvier和Executor的运行位置的不同划分的。client模式提交任务与Driver进程在同一个节点上,而cluster模式提交任务与Driver进程不在同一个节点。 Client模式 Clinet模式是在spark-submit提交任务的节点上运行Driver进程。 …

Dockerfile部署Java项目挂载使用外部配置文件

Dockerfile部署Java项目挂载使用外部配置文件 技术博客 http://idea.coderyj.com/ 需求是由于java项目使用的是nacos 而且每次部署nacos服务器ip不一样导致要重新打包,想引入外部配置文件进行打包 1.需求是由于java项目使用的是nacos 而且每次部署nacos服务器ip不一样导致要重新…

16ASM 汇编基础与Debug使用

目录 硬件运行机制 微机系统硬件组成 计算机系统组成 8086CPU组织结构 DoxBox安装 Debug使用 R命令 D命令 E命令 U命令 T命令 A命令 标志寄存器 常用机器指令 硬件运行机制 下面是一个电子器件二极管,正向加电则通,反向加电则不通 利用二…

Android : 序列化 Serializable 简单应用

1.Serializable 介绍: Serializable 是 Java 中的一个接口,它用于标记一个类或对象可以被序列化(即可以转换为字节流以便在网络上传输或在磁盘上持久化)。 当一个类实现 Serializable 接口时,它的对象可以被序列化,这…

AI创新之美:AIGC探讨2024年春晚吉祥物龙辰辰的AI绘画之独特观点

🎬 鸽芷咕:个人主页 🔥 个人专栏:《粉丝福利》 《linux深造日志》 ⛺️生活的理想,就是为了理想的生活! 文章目录 引言一、龙辰辰事件概述二、为什么龙辰辰会被质疑AI创作?1.1 AI 作画的特点2.2 关于建行的合作宣传图…

命令执行RCE及其绕过详细总结(17000+字数!)

目录 操作系统连接符&#xff1a; 常见函数&#xff1a; 绕过过滤&#xff1a; 空格过滤绕过&#xff1a; 1、大括号{}&#xff1a; 2、$IFS代替空格&#xff1a; 3、重定向字符<&#xff0c;<> 4、%09绕过&#xff08;相当于Tab键&#xff09; 文件名过滤绕过…

FPGA使用乘法的方式

FPGA使用乘法的方式 方法一:直接使用乘法符“*” 源代码 module multiply(input [7:0] a,input [7:0] b,output wire [15:0] result);(*use_dsp48 = "yes"*) wire [15:0] result;assign result = a*b; endmodule仿真代码 module multiply_tb();reg [7:0] a; re…