Skip to content

Commit b2743ab

Browse files
committed
new example using decorator to register strategy functions
1 parent c85c2cf commit b2743ab

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

docs/strategy.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@ Rethinking strategy
2525
-----------------
2626

2727
.. literalinclude:: ../exercises/strategy/strategy3.py
28+
29+
``strategy_best4.py``
30+
---------------------
31+
32+
.. literalinclude:: ../examples/strategy_best4.py

examples/strategy_best4.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# strategy_best4.py
2+
# Strategy pattern -- function-based implementation
3+
# selecting best promotion from list of functions
4+
# registered by a decorator
5+
6+
"""
7+
>>> joe = Customer('John Doe', 0)
8+
>>> ann = Customer('Ann Smith', 1100)
9+
>>> cart = [LineItem('banana', 4, .5),
10+
... LineItem('apple', 10, 1.5),
11+
... LineItem('watermellon', 5, 5.0)]
12+
>>> Order(joe, cart, fidelity)
13+
<Order total: 42.00 due: 42.00>
14+
>>> Order(ann, cart, fidelity)
15+
<Order total: 42.00 due: 39.90>
16+
>>> banana_cart = [LineItem('banana', 30, .5),
17+
... LineItem('apple', 10, 1.5)]
18+
>>> Order(joe, banana_cart, bulk_item)
19+
<Order total: 30.00 due: 28.50>
20+
>>> long_order = [LineItem(str(item_code), 1, 1.0)
21+
... for item_code in range(10)]
22+
>>> Order(joe, long_order, large_order)
23+
<Order total: 10.00 due: 9.30>
24+
>>> Order(joe, cart, large_order)
25+
<Order total: 42.00 due: 42.00>
26+
27+
# BEGIN STRATEGY_BEST_TESTS
28+
29+
>>> Order(joe, long_order, best_promo)
30+
<Order total: 10.00 due: 9.30>
31+
>>> Order(joe, banana_cart, best_promo)
32+
<Order total: 30.00 due: 28.50>
33+
>>> Order(ann, cart, best_promo)
34+
<Order total: 42.00 due: 39.90>
35+
36+
# END STRATEGY_BEST_TESTS
37+
"""
38+
39+
from collections import namedtuple
40+
41+
Customer = namedtuple('Customer', 'name fidelity')
42+
43+
44+
class LineItem:
45+
46+
def __init__(self, product, quantity, price):
47+
self.product = product
48+
self.quantity = quantity
49+
self.price = price
50+
51+
def total(self):
52+
return self.price * self.quantity
53+
54+
55+
class Order: # the Context
56+
57+
def __init__(self, customer, cart, promotion=None):
58+
self.customer = customer
59+
self.cart = list(cart)
60+
self.promotion = promotion
61+
62+
def total(self):
63+
if not hasattr(self, '__total'):
64+
self.__total = sum(item.total() for item in self.cart)
65+
return self.__total
66+
67+
def due(self):
68+
if self.promotion is None:
69+
discount = 0
70+
else:
71+
discount = self.promotion(self)
72+
return self.total() - discount
73+
74+
def __repr__(self):
75+
fmt = '<Order total: {:.2f} due: {:.2f}>'
76+
return fmt.format(self.total(), self.due())
77+
78+
# BEGIN STRATEGY_BEST4
79+
80+
promos = [] # <1>
81+
82+
def promotion(promo_func): # <2>
83+
promos.append(promo_func)
84+
return promo_func
85+
86+
@promotion # <3>
87+
def fidelity(order):
88+
"""5% discount for customers with 1000 or more fidelity points"""
89+
return order.total() * .05 if order.customer.fidelity >= 1000 else 0
90+
91+
@promotion
92+
def bulk_item(order):
93+
"""10% discount for each LineItem with 20 or more units"""
94+
discount = 0
95+
for item in order.cart:
96+
if item.quantity >= 20:
97+
discount += item.total() * .1
98+
return discount
99+
100+
@promotion
101+
def large_order(order):
102+
"""7% discount for orders with 10 or more distinct items"""
103+
distinct_items = {item.product for item in order.cart}
104+
if len(distinct_items) >= 10:
105+
return order.total() * .07
106+
return 0
107+
108+
def best_promo(order): # <4>
109+
"""Select best discount available
110+
"""
111+
return max(promo(order) for promo in promos)
112+
113+
# END STRATEGY_BEST4

0 commit comments

Comments
 (0)