在前文 设计模式 - 装饰模式 中比较全面地介绍了什么是装饰模式
,介绍了设计模式 - 装饰模式
优缺点、适用范围。
现在简单实现一下,加深学习印象。
我们可以这样理解:
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰模式特点
- 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
- 装饰对象包含一个真实对象的引用(reference)
- 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
- 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
真实对象区别于抽象对象(Component)。抽象对象不应该被具体实现;同时修饰类引用和继承 Component 类,具体扩展类重写父类方法。
设计原则
- 应当多组合,少继承
利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。
- 类的设计应该对扩展开放,对修改关闭
样例实现
在这个样例中,主要体会对子类的组合实现,以及深入体会如何动态加载子类
from functools import wraps
def login_check(func):
"""
Decorator
check whether user is logged in
:param func
:return wrapper
"""
@wraps(func)
def wrapper(*args, **kwargs):
if args[0].status != "login":
print("User hasn't logged in yet!")
else:
return func(*args, **kwargs)
return wrapper
class Visitor(object):
def __init__(self, status) -> None:
self.status = status
# decorate this method
@login_check
def access_allow(self):
print("User now has login. Access is allowed")
if __name__ == "__main__":
print('>>> set status login, is result')
visitor = Visitor('login')
visitor.access_allow()
print('>>> set status not login, below is result')
visitor = Visitor('visitor')
visitor.access_allow()
Console Output : > set status login, is result [LOGIN RESULT] User now has login. Access is allowed >set status not login, below is result [LOGIN RESULT] User hasn’t logged in yet!
接下来新增一个函数,命名为logger
,目的是显示日志,当他装饰的函数被调用时,就会记录日志,内容包括函数名以及函数参数。
from functools import wraps
def login_check(func):
...
def logger(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"{func.__name__} was called. Parmas: {str(args)}, {str(kwargs)}")
return func(*args, **kwargs)
return wrapper
class Visitor(object):
def __init__(self, status) -> None:
self.status = status
# decorate this method
@logger
@login_check
def access_allow(self):
print("[LOGIN RESULT] User now has login. Access is allowed")
if __name__ == "__main__":
print('> set status login, is result')
visitor = Visitor('login')
visitor.access_allow()
print('> set status not login, below is result')
visitor = Visitor('visitor')
visitor.access_allow()
Console Output : > set status login, is result access_allow was called. Parmas: (<main.Visitor object at 0x0000019BCE620F70>,), {} [LOGIN RESULT] User now has login. Access is allowed >set status not login, below is result access_allow was called. Parmas: (<main.Visitor object at 0x0000019BCE620730>,), {} [LOGIN RESULT] User hasn’t logged in yet!