|
3 | 3 |
|
4 | 4 | """
|
5 | 5 | *What is this pattern about?
|
6 |
| -This pattern aims to encapsulate each algorithm and allow them to be |
7 |
| -interchangeable. Separating algorithms allows the client to scale |
8 |
| -with larger and more complex algorithms, since the client and the |
9 |
| -strategies are kept independent of each other. |
10 |
| -
|
11 |
| -Having the algorithms as an integral part of the client can cause the |
12 |
| -client to be larger and harder to maintain. This is more evident when |
13 |
| -supporting multiple algorithms. The separation of client and algorithm |
14 |
| -allows us to easily replace and vary the algorithm. |
15 |
| -
|
16 |
| -*What does this example do? |
17 |
| -Below the 'StrategyExample' is an example of the client while the two |
18 |
| -functions; 'execute_replacement1' and 'execute_replacement2' are |
19 |
| -examples of the implementation or strategy. In the example we can see |
20 |
| -that the client can vary it's 'execute' method by changing the |
21 |
| -strategy which is responsible for implementation. |
22 |
| -
|
23 |
| -http://stackoverflow.com/questions/963965/how-is-this-strategy-pattern |
24 |
| - -written-in-python-the-sample-in-wikipedia |
25 |
| -In most of other languages Strategy pattern is implemented via creating some |
26 |
| -base strategy interface/abstract class and subclassing it with a number of |
27 |
| -concrete strategies (as we can see at |
28 |
| -http://en.wikipedia.org/wiki/Strategy_pattern), however Python supports |
29 |
| -higher-order functions and allows us to have only one class and inject |
30 |
| -functions into it's instances, as shown in this example. |
| 6 | +Define a family of algorithms, encapsulate each one, and make them interchangeable. |
| 7 | +Strategy lets the algorithm vary independently from clients that use it. |
31 | 8 |
|
32 | 9 | *TL;DR80
|
33 | 10 | Enables selecting an algorithm at runtime.
|
34 | 11 | """
|
35 | 12 |
|
36 |
| -import types |
37 |
| - |
38 |
| - |
39 |
| -class StrategyExample: |
40 |
| - def __init__(self, func=None): |
41 |
| - self.name = 'Strategy Example 0' |
42 |
| - if func is not None: |
43 |
| - self.execute = types.MethodType(func, self) |
44 |
| - |
45 |
| - def execute(self): |
46 |
| - print(self.name) |
47 | 13 |
|
| 14 | +class Order: |
| 15 | + def __init__(self, price, discount_strategy=None): |
| 16 | + self.price = price |
| 17 | + self.discount_strategy = discount_strategy |
48 | 18 |
|
49 |
| -def execute_replacement1(self): |
50 |
| - print(self.name + ' from execute 1') |
| 19 | + def price_after_discount(self): |
| 20 | + if self.discount_strategy: |
| 21 | + discount = self.discount_strategy(self) |
| 22 | + else: |
| 23 | + discount = 0 |
| 24 | + return self.price - discount |
51 | 25 |
|
| 26 | + def __repr__(self): |
| 27 | + fmt = "<Price: {}, price after discount: {}>" |
| 28 | + return fmt.format(self.price, self.price_after_discount()) |
52 | 29 |
|
53 |
| -def execute_replacement2(self): |
54 |
| - print(self.name + ' from execute 2') |
55 | 30 |
|
| 31 | +def ten_percent_discount(order): |
| 32 | + return order.price * 0.10 |
56 | 33 |
|
57 |
| -if __name__ == '__main__': |
58 |
| - strat0 = StrategyExample() |
59 | 34 |
|
60 |
| - strat1 = StrategyExample(execute_replacement1) |
61 |
| - strat1.name = 'Strategy Example 1' |
| 35 | +def on_sale_discount(order): |
| 36 | + return order.price * 0.25 + 20 |
62 | 37 |
|
63 |
| - strat2 = StrategyExample(execute_replacement2) |
64 |
| - strat2.name = 'Strategy Example 2' |
65 | 38 |
|
66 |
| - strat0.execute() |
67 |
| - strat1.execute() |
68 |
| - strat2.execute() |
| 39 | +if __name__ == "__main__": |
| 40 | + order0 = Order(100) |
| 41 | + order1 = Order(100, discount_strategy=ten_percent_discount) |
| 42 | + order2 = Order(1000, discount_strategy=on_sale_discount) |
| 43 | + print(order0) |
| 44 | + print(order1) |
| 45 | + print(order2) |
69 | 46 |
|
70 | 47 | ### OUTPUT ###
|
71 |
| -# Strategy Example 0 |
72 |
| -# Strategy Example 1 from execute 1 |
73 |
| -# Strategy Example 2 from execute 2 |
| 48 | +# <Price: 100, price after discount: 100> |
| 49 | +# <Price: 100, price after discount: 90.0> |
| 50 | +# <Price: 1000, price after discount: 730.0> |
0 commit comments