【八】python装饰器模式

文章目录

  • [8.1 装饰器模式简介](#8.1 装饰器模式简介)
  • [8.2 装饰器模式作用](#8.2 装饰器模式作用)
  • [8.3 装饰器模式构成](#8.3 装饰器模式构成)
    • [8.3.1 装饰器模式包含以下几个核心角色:](#8.3.1 装饰器模式包含以下几个核心角色:)
    • [8.3.2 UML类图](#8.3.2 UML类图)
  • [8.4 装饰器模式python代码实现](#8.4 装饰器模式python代码实现)
    • [8.4.1 基本装饰器的使用](#8.4.1 基本装饰器的使用)
    • [8.4.2 多个装饰器的执行顺序](#8.4.2 多个装饰器的执行顺序)
    • [8.4.3 带返回值的装饰器的使用](#8.4.3 带返回值的装饰器的使用)
    • [8.4.4 装饰器模式-关联类模式](#8.4.4 装饰器模式-关联类模式)
    • [8.4.5 装饰器模式-无参数](#8.4.5 装饰器模式-无参数)
    • [8.4.6 装饰器模式-接收原函数参数](#8.4.6 装饰器模式-接收原函数参数)
    • [8.4.7 装饰器模式-装饰器自带函数](#8.4.7 装饰器模式-装饰器自带函数)
    • [8.4.8 装饰器模式应用-事务提交与回滚](#8.4.8 装饰器模式应用-事务提交与回滚)
  • [8.5 装饰器模式优点与缺点](#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 基本装饰器的使用

python 复制代码
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 多个装饰器的执行顺序

python 复制代码
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 带返回值的装饰器的使用

python 复制代码
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 装饰器模式-关联类模式

python 复制代码
# 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 装饰器模式-无参数

python 复制代码
# 装饰器--无参数
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 装饰器模式-接收原函数参数

python 复制代码
# 装饰器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 装饰器模式-装饰器自带函数

python 复制代码
# 装饰器
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 装饰器模式应用-事务提交与回滚

在事务处理中,装饰器模式可以用于在执行数据库操作之前和之后执行一些附加的操作,例如日志记录、验证、事务管理等。下面是一个使用装饰器模式实现事务处理的示例:

python 复制代码
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 装饰器模式优点与缺点

  • 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
  • 缺点:多层装饰比较复杂。
相关推荐
yusaisai大鱼3 分钟前
tensorflow_probability与tensorflow版本依赖关系
人工智能·python·tensorflow
Biomamba生信基地7 分钟前
R语言基础| 功效分析
开发语言·python·r语言·医药
手可摘星河9 分钟前
php中 cli和cgi的区别
开发语言·php
CodeClimb22 分钟前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
夜幕龙29 分钟前
iDP3复现代码数据预处理全流程(二)——vis_dataset.py
人工智能·python·机器人
CT随32 分钟前
Redis内存碎片详解
java·开发语言
anlog41 分钟前
C#在自定义事件里传递数据
开发语言·c#·自定义事件
奶香臭豆腐1 小时前
C++ —— 模板类具体化
开发语言·c++·学习
晚夜微雨问海棠呀1 小时前
长沙景区数据分析项目实现
开发语言·python·信息可视化
graceyun1 小时前
C语言初阶习题【9】数9的个数
c语言·开发语言