Design Patterns——<四>装饰模式

文章目录

  • 一、什么是装饰模式?
  • 二、代码框架
  • 三、Python中的装饰器
    • 1 定义内部函数并返回
    • 2 装饰器修饰函数
    • 3 装饰器修饰类
  • 补充说明
    • Python装饰器 vs 装饰模式

一、什么是装饰模式?

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
动态地给一个对象增加一些额外的职责,就拓展对象功能来说,装饰模式比生成子类的方式更为灵活。


二、代码框架

Design Patterns——<四>装饰模式_第1张图片

装饰模式UML类图

三、Python中的装饰器

在Python中一切都是对象:一个实例、一个函数甚至类本身,可以将一个函数作为参数传给另一个函数,也可以将一个类作为参数传给一个函数。

1 定义内部函数并返回

def func(num):
    '''定义内部函数并返回'''
    
    def firstInnerFunc():
        return 'This is the first inner function.'
    
    def secondInnerFunc():
        return 'This is the second inner function.'
    
    if num == 1:
        return firstInnerFunc
    else:
        return secondInnerFunc
    
print(func(1))
print(func(2))
print(func(1)())
print(func(2)())

上面的代码等同于:

firstFunc = func(1)
secondFunc = func(2)

print(firstFunc)
print(secondFunc)
print(firstFunc())
print(secondFunc())

输出:

.firstInnerFunc at 0x000002CF4EC51630>
.secondInnerFunc at 0x000002CF4EC516C0>
This is the first inner function.
This is the second inner function.

2 装饰器修饰函数

'''
@author: zyh
@file: demo_decorate_func.py

装饰器修饰函数的例子。
'''
import logging
logging.basicConfig(level=logging.INFO)

def loggingDecorator(func):
    '''记录日志的装饰器'''
    def wrapperLogging(*args, **kwargs):
        logging.info('开始执行 %s() ...'%func.__name__)
        func(*args, **kwargs)
        logging.info('%s() 执行完成!'%func.__name__)
    return wrapperLogging

@loggingDecorator
def showMin(a,b):
    print('%d, %d 中的最小值是: %d' % (a, b, min(a,b)))
    
# decoratedShowMin = loggingDecorator(showMin)
# decoratedShowMin(2,3)
showMin(2,3)

以下两段代码等价:

@loggingDecorator
def showMin(a,b):
    print('%d, %d 中的最小值是: %d' % (a, b, min(a,b)))
showMin(2,3)
def showMin(a,b):
    print('%d, %d 中的最小值是: %d' % (a, b, min(a,b)))
    
decoratedShowMin = loggingDecorator(showMin)
decoratedShowMin(2,3)

输出:

INFO:root:开始执行 showMin() ...
2, 3 中的最小值是: 2
INFO:root:showMin() 执行完成!

3 装饰器修饰类

装饰器可以是一个函数,也可以是一个类(必须要实现__call__方法,使其是callable的)。装饰器不仅可以修饰函数,也可以修饰类。

'''
@author: zyh
@file: demo_decorate_class.py
@time: 2023/5/9 15:47

装饰器修饰类的例子。
'''
class ClassDecorator:
    '''类装饰器,记录一个类被实例化的次数'''
    def __init__(self, func):
        self._numOfCall = 0
        self._func = func
        
    def __call__(self, *args, **kwargs):
        self._numOfCall += 1
        obj = self._func(*args, **kwargs)
        print('创建%s 的第%d 个实例: %s'%(self._func.__name__, self._numOfCall, id(obj)))
        return obj
        
@ClassDecorator
class MyClass:
    def __init__(self, name):
        self._name = name
        
    def getName(self):
        return self._name
    
tony = MyClass('Tony')
billy = MyClass('Billy')
print(id(tony))
print(id(billy))

输出:

创建MyClass 的第1 个实例: 2963514621424
创建MyClass 的第2 个实例: 2963514621328
2963514621424
2963514621328

补充说明

装饰模式的优点:

  1. 使用装饰模式实现拓展比使用继承更加灵活,可以在不创造更多子类的情况下,将对象的功能加以拓展;
  2. 可以动态地为一个对象附加功能;
  3. 可以用不同的装饰器进行多重装饰,装饰的顺序不同可能产生不同的效果;
  4. 装饰类和被装饰类解耦。

装饰模式相当于继承的一个替代模式。

缺点:

相比继承更容易出错,排错也更加困难。


Python装饰器 vs 装饰模式

Python装饰器与装饰模式的设计思想相似,其目标均为更好的拓展性。

区别点
Python装饰器
装饰模式
设计思想 函数式编程思想,即面向过程的思想 面向对象
修饰的对象 函数、类 某个类中的指定方法
影响范围 修饰一个函数时,对这个函数的所有调用都起效;修饰一个类时,对这个类的所有实例都起效 仅对修饰的这一个对象起效

你可能感兴趣的:(设计模式,Python,设计模式,python)