装饰器模式实现起来跟代理模式差多,其实可以是一样的,看你把它置于什么场景。代理模式侧重于隔离客户与被代理者,通过代理者控制访问被代理者的权限,而装饰器模式侧重于给被装饰的对象提供附加的功能,例如加上日志功能。python 语法层面就提供了装饰器,足以说明装饰器模式的重要性,这里我们就直接介绍python的装饰器吧。
先看看函数装饰器:
def work_wrapper(w):
def func(*args, **kwargs):
print('logging start ...')
w(*args, **kwargs)
print('logging end ...')
return func
@work_wrapper
def work():
print('working')
if __name__ == '__main__':
work()
输出:
logging start ...
working
logging end ...
@符号是装饰器的标志,函数work
上加一行@work_wrapper
的意思是 work = work_wrapper(work)
。装饰器可以叠加,我们修改下:
def work_wrapper_a(w):
def func(*args, **kwargs):
print('a logging start ...')
w(*args, **kwargs)
print('a logging end ...')
return func
def work_wrapper_b(w):
def func(*args, **kwargs):
print('b logging start ...')
w(*args, **kwargs)
print('b logging end ...')
return func
@work_wrapper_b
@work_wrapper_a
def work():
print('working')
if __name__ == '__main__':
work()
输出
b logging start ...
a logging start ...
working
a logging end ...
b logging end ...
装饰器还可以带参数,如下:
def work_para_wrapper(work_times):
def work_wrapper(w):
def func(*args, **kwargs):
print('logging start ...')
[w(*args, **kwargs) for i in range(work_times)]
print('logging end ...')
return func
return work_wrapper
@work_para_wrapper(3)
def work():
print('working')
if __name__ == '__main__':
work()
其实跟不带参数的装饰器原理一样,work_para_wrapper(3)
会返回一个不带参数装饰器。不但函数可以应用装饰器,类也可以,看下面例子:
def worker_wrapper(cls):
class WorkerEnhanced(cls):
def learn(self):
print('learning new things, {}'.format(self._name))
return WorkerEnhanced
@worker_wrapper
class Worker:
def __init__(self, name):
self._name = name
def work(self):
print('working')
if __name__ == '__main__':
w = Worker('Jack')
print(type(w))
w.learn()
输出
<class '__main__.worker_wrapper.<locals>.WorkerEnhanced'>
learning new things, Jack
另外,利用类的魔术方法 __call__
,类也可以作为装饰器。
class WorkerEnhanced:
def __init__(self, worker):
self._worker = worker()
def __call__(self, name):
self._worker.Name = name
return self
def learn(self):
print('{} is learning new things'.format(self._worker.Name))
def work(self):
self._worker.work()
@WorkerEnhanced
class Worker:
def __init__(self, name=None):
self._name = name
@property
def Name(self):
return self._name
@Name.setter
def Name(self, val):
self._name = val
def work(self):
print('{} is working'.format(self._name))
if __name__ == '__main__':
w = Worker('Jack')
print(type(w))
w.work()
w.learn()
输出:
<class '__main__.WorkerEnhanced'>
Jack is working
Jack is learning new things
这个例子没什么意义,只是为了说明下怎么使用类来装饰类。最后强调一下,不论是函数装饰器还是类装饰器,原理都是同一个 @ d e c o r a t e t o _ b e _ d e c o r a t e d \frac{@decorate}{to\_be\_decorated} to_be_decorated@decorate ==> t o _ b e _ d e c o r a t e d = d e c o r a t e ( t o _ b e _ d e c o r a t e d ) to\_be\_decorated = decorate(to\_be\_decorated) to_be_decorated=decorate(to_be_decorated)