装饰器模式
# 注意
装饰器模式不等于装饰器。
以支持动态地(运行时)扩展一个对象的功能,这种方法就是装饰器。装饰器(Decorator)模式能够以透明的方式(不会影响其他对象)动态地将功能添加到一个对象中(请参考[GOF95,第 196 页])。 在许多编程语言中,使用子类化(继承)来实现装饰器模式(请参考[GOF95,第 198 页])。 在 Python 中,我们可以(并且应该)使用内置的装饰器特性。一个 Python 装饰器就是对 Python 语法的一个特定改变,用于扩展一个类、方法或函数的行为,而无需使用继承。从实现的角度来说,Python 装饰器是一个可调用对象(函数、方法、类),接受一个函数对象 fin 作为输入,并返回另一个函数对象 。这意味着可以将任何具有这些属性的可调用对象当作一个装饰器。 装饰器模式和 Python 装饰器之间并不是一对一的等价关系。Python 装饰器能做的实际上比装饰器模式多得多,其中之一就是实现装饰器模式。
# 作用
Adds behaviour to object without affecting its class.
Decorator 模式用于动态地向对象添加新特性,而不更改其原来的代码实现。它与继承不同,新特性只绑定到特定对象,而不会添加到整个子类。
# 优缺点
# 优点
- 你无需创建新子类即可扩展对象的行为。
- 你可以在运行时添加或删除对象的功能。
- 你可以用多个装饰封装对象来组合几种行为。
- 单一职责原则。 你可以将实现了许多不同行为的一个大类拆分为多个较小的类。
# 缺点
- 在封装器栈中删除特定封装器比较困难。
- 实现行为不受装饰栈顺序影响的装饰比较困难。
- 各层的初始化配置代码看上去可能会很糟糕。
# 代码
"""
*What is this pattern about?
The Decorator pattern is used to dynamically add a new feature to an
object without changing its implementation. It differs from
inheritance because the new feature is added only to that particular
object, not to the entire subclass.
*What does this example do?
This example shows a way to add formatting options (boldface and
italic) to a text by appending the corresponding tags (<b> and
<i>). Also, we can see that decorators can be applied one after the other,
since the original text is passed to the bold wrapper, which in turn
is passed to the italic wrapper.
*Where is the pattern used practically?
The Grok framework uses decorators to add functionalities to methods,
like permissions or subscription to an event:
http://grok.zope.org/doc/current/reference/decorators.html
*References:
https://sourcemaking.com/design_patterns/decorator
*TL;DR
Adds behaviour to object without affecting its class.
"""
class TextTag:
"""Represents a base text tag"""
def __init__(self, text: str) -> None:
self._text = text
def render(self) -> str:
return self._text
class BoldWrapper(TextTag):
"""Wraps a tag in <b>"""
def __init__(self, wrapped: TextTag) -> None:
self._wrapped = wrapped
def render(self) -> str:
return f"<b>{self._wrapped.render()}</b>"
class ItalicWrapper(TextTag):
"""Wraps a tag in <i>"""
def __init__(self, wrapped: TextTag) -> None:
self._wrapped = wrapped
def render(self) -> str:
return f"<i>{self._wrapped.render()}</i>"
def main():
"""
>>> simple_hello = TextTag("hello, world!")
>>> special_hello = ItalicWrapper(BoldWrapper(simple_hello))
>>> print("before:", simple_hello.render())
before: hello, world!
>>> print("after:", special_hello.render())
after: <i><b>hello, world!</b></i>
"""
if __name__ == "__main__":
import doctest
doctest.testmod()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
ref: patterns/structural/decorator.py · imoyao/python-patterns - Gitee.com (opens new window)
编辑 (opens new window)
上次更新: 2024-07-15, 03:27:09