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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

「C++」内存管理

🎇个人主页:Ice_Sugar_7 🎇所属专栏:C启航 🎇欢迎点赞收藏加关注哦! 文章目录 🍉内存分布🍉关键字new🍉关键字delete🍉new和delete的封装实现🍉总…

牛客——不重复数字(哈希表、平衡树)

今天的第二题。下面这道题呢有两种解法,一种基于哈希表,一种基于平衡树。 登录—专业IT笔试面试备考平台_牛客网 题目描述 给出N个数,要求把其中重复的去掉,只保留第一次出现的数。 例如,给出的数为1 2 18 3 3 …

接口测试要测试什么?怎么测?

本文主要分为两个部分: 第一部分:主要从问题出发,引入接口测试的相关内容并与前端测试进行简单对比,总结两者之前的区别与联系 第二部分:主要介绍为什么要做接口测试,并简单总结接口持续集成和接口质量评估…

Java调用百度翻译API和调用有道翻译API进行翻译

目录 界面编写 调用百度API 调用有道API 源代码 界面编写 我们首先需要设计出这个翻译程序的GUI界面,我们写一个类继承自JFrame类,用来展示程序的主窗口,设置好窗口的名称和大小,设置在关闭窗口时终止程序,为了界…

React Native:入门知识了解

什么是React Native React Native(简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。React Native使用Javascript语言&am…

功能更新|免费敏捷工具Leangoo领歌私有部署新增第三方身份认证和API对接

Leangoo领歌是一款永久免费的专业的敏捷开发管理工具,提供端到端敏捷研发管理解决方案,涵盖敏捷需求管理、任务协同、进展跟踪、统计度量等。 Leangoo支持敏捷研发管理全流程,包括小型团队敏捷开发,规模化敏捷SAFe,Scr…

windows数据备份方法

信息时代数据已成为个人及企业的重要资产,数据丢失或者损坏会带来无法弥补的损失。数据安全主要关注两个方面数据容灾和数据备份。容灾的目的是防止硬件发生错误,通过多个相同或类似硬件避免单一硬件故障造成的数据丢失。数据备份除了可以防止单一硬件错…

使用QT基于YMODEM协议实现串口文件发送(和xshell互通)

背景 项目需要用QT实现一个YMODEM文件传输的功能,目标下位机是MCU嵌入式设备,且下位机程序已经经过xshell传输文件的验证。 YMODEM 简介 YMODEM协议是一个文件传输协议,常用于嵌入式设备。本文不对YMODEM做过多的阐述,阅读需建…

Tomcat主配置文件(server.xml)详解

前言 Tomcat主配置文件(server.xml)是Tomcat服务器的主要配置文件,文件位置在conf目录下,它包含了Tomcat的全局配置信息,包括监听端口、虚拟主机、安全配置、连接器等。 目录 1 server.xml组件类别 2 组件介绍 3 se…

003 FeedForward前馈层

一、环境 本文使用环境为: Windows10Python 3.9.17torch 1.13.1cu117torchvision 0.14.1cu117 二、前馈层原理 Transformer模型中的前馈层(Feed Forward Layer)是其关键组件之一,对于模型的性能起着重要作用。下面将用900字对…

cpp:1:10: fatal error: opencv2/core.hpp: 没有那个文件或目录

前言&#xff1a; 我按照官网方法安装了opencv&#xff0c;运行的也是官网的测试代码&#xff1a; #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> using namespace cv; int main() {printf("hello world")return 0; }

boost1.55 安装使用教程 windows

第一步 &#xff1a;首先在boost官网上下载库压缩包 添加链接描述 选择自己需要的版本进行下载 解压后执行booststrap.bat 用来生成创建b2.exe 和bjam.exe 拓展&#xff1a;.\b2 --help 了解一下有哪些参数可以配置 默认b2.exe编译后&#xff0c;链接到项目如果出现如下错误…

VLAN基本原理

目录 一、VLAN概念及优势 &#xff08;一&#xff09;基本理念 &#xff08;二&#xff09;VLAN的特点 二、VLAN ID 种类、范围及用途 &#xff08;一&#xff09;静态VLAN &#xff08;二&#xff09;动态VLAN &#xff08;三&#xff09;VLAN三种端口类型 &#xff0…

深入理解Java虚拟机---类加载机制

类加载机制 什么是类加载机制类加载的时机类加载的过程加载验证文件格式验证元数据验证字节码验证符号引用验证 准备解析初始化 类加载器双亲委派模型 什么是类加载机制 虚拟机把描述类的数据从 Class 文件加载到内存&#xff0c;并对数据进行校验、转换解析和初始化&#xff…

centOS安装bochsXshell连接centos启动可视化界面

centOS安装bochs 参考&#xff1a;https://blog.csdn.net/muzi_since/article/details/102559187 首先安装依赖环境&#xff1a; yum install gtk2 gtk2-devel yum install libXt libXt-devel yum install libXpm libXpm-devel yum install SDL SDL-devel yum install libXr…

已解决:No goals have been specified for this build. You must specify a vali

[ERROR] No goals have been specified for this build. You must specify a valiTOC 完整报错 No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format : or :[:]:. Available lifecycle phases are: pre-clean, c…

6. Service详解

6. Service详解 文章目录 6. Service详解6.1 Service介绍6.2 Service类型6.3 Service使用6.3.1 实验环境准备6.3.2 ClusterIP类型的Service6.3.3 HeadLess类型的Service6.3.3.1 deployment和statefulset区别6.3.3.2 statefulset deployment 区别 6.3.4 NodePort类型的Service6.…

Trace 在多线程异步体系下传递

JAVA 线程异步常见的实现方式有&#xff1a; new ThreadExecutorService 当然还有其他的&#xff0c;比如fork-join&#xff0c;这些下文会有提及&#xff0c;下面主要针对这两种场景结合 DDTrace 和 Springboot 下进行实践。 引入 DDTrace sdk <properties><java.…

湖农大邀请赛shell_rce漏洞复现

湖农大邀请赛 shell_rce 复现 在 2023 年湖南农业大学邀请赛的线上初赛中&#xff0c;有一道 shell_rce 题&#xff0c;本文将复现该题。 题目内容&#xff0c;打开即是代码&#xff1a; <?phpclass shell{public $exp;public function __destruct(){$str preg_replace…

Shopify怎么避免被封店?封店原因有哪些?

市场研究的一份报告显示&#xff0c;全球跨境电子商务市场预计到2028年将达到30422亿美元&#xff0c;其中&#xff0c;亚太地区是最大的跨境电商市场&#xff0c;据海关统计数据&#xff0c;近五年来&#xff0c;我国跨境电商进出口增长近10倍。跨境电商业务新的增长风口已经到…