【八】python装饰器模式
2023-12-13 11:44:17
文章目录
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 装饰器模式优点与缺点
- 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
- 缺点:多层装饰比较复杂。
文章来源:https://blog.csdn.net/ljllxk001/article/details/134943799
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!