设计模式(7)——策略模式
本文介绍策略模式的概念和应用。
# 基本思想和原则
定义一组算法,将每个算法都封装起来,使它们之间可以互换。
策略模式(Strategy pattern)鼓励使用多种算法来解决一个问题,其杀手级特性是能够在运行时透明地切换算法(客户端代码对变化无感知)。因此,如果你有两种算法,并且知道其中一种对少量输入效果更好,另一种对大量输入效果更好,则可以使用策略模式在运行时基于输入数据决定使用哪种算法
# 动机
当一个操作中可以使用多种算法相互替换时,可以挨个实现各个算法,然后用一个上下文封装起来,当需要执行操作时,选择一个策略传入上下文即可。
# 实现
from __future__ import annotations
from typing import Callable
class DiscountStrategyValidator: # Descriptor class for check perform
@staticmethod
def validate(obj: Order, value: Callable) -> bool:
try:
if obj.price - value(obj) < 0:
raise ValueError(
f"Discount cannot be applied due to negative price resulting. {value.__name__}"
)
except ValueError as ex:
print(str(ex))
return False
else:
return True
def __set_name__(self, owner, name: str) -> None:
self.private_name = f"_{name}"
def __set__(self, obj: Order, value: Callable = None) -> None:
if value and self.validate(obj, value):
setattr(obj, self.private_name, value)
else:
setattr(obj, self.private_name, None)
def __get__(self, obj: object, objtype: type = None):
return getattr(obj, self.private_name)
class Order:
discount_strategy = DiscountStrategyValidator()
def __init__(self, price: float, discount_strategy: Callable = None) -> None:
self.price: float = price
self.discount_strategy = discount_strategy
def apply_discount(self) -> float:
if self.discount_strategy:
discount = self.discount_strategy(self)
else:
discount = 0
return self.price - discount
def __repr__(self) -> str:
return f"<Order price: {self.price} with discount strategy:
{getattr(self.discount_strategy,'__name__',None)}>"
def ten_percent_discount(order: Order) -> float:
return order.price * 0.10
def on_sale_discount(order: Order) -> float:
return order.price * 0.25 + 20
def main():
"""
>>> order = Order(100, discount_strategy=ten_percent_discount)
>>> print(order)
<Order price: 100 with discount strategy: ten_percent_discount>
>>> print(order.apply_discount())
90.0
>>> order = Order(100, discount_strategy=on_sale_discount)
>>> print(order)
<Order price: 100 with discount strategy: on_sale_discount>
>>> print(order.apply_discount())
55.0
>>> order = Order(10, discount_strategy=on_sale_discount)
Discount cannot be applied due to negative price resulting. on_sale_discount
>>> print(order)
<Order price: 10 with discount strategy: None>
"""
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
76
77
78
79
80
81
82
83
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
76
77
78
79
80
81
82
83
可以看到策略模式和工厂模式很像。但其实两个的差别很微妙,工厂模式是直接创建具体的对象并用该对象去执行相应的动作。简单工厂模式侧重于生成对象。
而策略模式将这个操作给了 Context 类,没有创建具体的对象,实现的代码的进一步封装,客户端代码并不需要知道具体的实现过程。 策略模式中注重具体算法的实现。
一个创建型模式,一个行为型模式。
# 优点
策略模式中各种算法可以随意切换,想要替换一个算法非常简单,当需要增加新的算法时,只要创建一个新类实现相应接口即可直接使用,同时也避免了在上下文中使用条件判断语句来选择具体算法。
# 缺点
如果有大量算法,策略模式中可能会有非常多的具体算法类,并且上层模块需要了解每个策略模式的具体算法。
# 参考来源
编辑 (opens new window)
上次更新: 2024-07-15, 03:27:09