Created
May 17, 2015 23:19
-
-
Save douglasmiranda/9a47f9564d1c64e73c45 to your computer and use it in GitHub Desktop.
ppqsp - implement register decorator on example from https://github.com/fluentpython/example-code/blob/master/06-dp-1class-func/strategy_best.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# strategy_best.py | |
# Strategy pattern -- function-based implementation | |
# selecting best promotion from static list of functions | |
""" | |
>>> joe = Customer('John Doe', 0) | |
>>> ann = Customer('Ann Smith', 1100) | |
>>> cart = [LineItem('banana', 4, .5), | |
... LineItem('apple', 10, 1.5), | |
... LineItem('watermellon', 5, 5.0)] | |
>>> Order(joe, cart, fidelity_promo) | |
<Order total: 42.00 due: 42.00> | |
>>> Order(ann, cart, fidelity_promo) | |
<Order total: 42.00 due: 39.90> | |
>>> banana_cart = [LineItem('banana', 30, .5), | |
... LineItem('apple', 10, 1.5)] | |
>>> Order(joe, banana_cart, bulk_item_promo) | |
<Order total: 30.00 due: 28.50> | |
>>> long_order = [LineItem(str(item_code), 1, 1.0) | |
... for item_code in range(10)] | |
>>> Order(joe, long_order, large_order_promo) | |
<Order total: 10.00 due: 9.30> | |
>>> Order(joe, cart, large_order_promo) | |
<Order total: 42.00 due: 42.00> | |
# BEGIN STRATEGY_BEST_TESTS | |
>>> Order(joe, long_order, best_promo) # <1> | |
<Order total: 10.00 due: 9.30> | |
>>> Order(joe, banana_cart, best_promo) # <2> | |
<Order total: 30.00 due: 28.50> | |
>>> Order(ann, cart, best_promo) # <3> | |
<Order total: 42.00 due: 39.90> | |
# END STRATEGY_BEST_TESTS | |
""" | |
from collections import namedtuple | |
Customer = namedtuple('Customer', 'name fidelity') | |
PROMOS = [] | |
def register_promotion(func): | |
PROMOS.append(func) | |
return func | |
class LineItem: | |
def __init__(self, product, quantity, price): | |
self.product = product | |
self.quantity = quantity | |
self.price = price | |
def total(self): | |
return self.price * self.quantity | |
class Order: # the Context | |
def __init__(self, customer, cart, promotion=None): | |
self.customer = customer | |
self.cart = list(cart) | |
self.promotion = promotion | |
def total(self): | |
if not hasattr(self, '__total'): | |
self.__total = sum(item.total() for item in self.cart) | |
return self.__total | |
def due(self): | |
if self.promotion is None: | |
discount = 0 | |
else: | |
discount = self.promotion(self) | |
return self.total() - discount | |
def __repr__(self): | |
fmt = '<Order total: {:.2f} due: {:.2f}>' | |
return fmt.format(self.total(), self.due()) | |
@register_promotion | |
def fidelity_promo(order): | |
"""5% discount for customers with 1000 or more fidelity points""" | |
return order.total() * .05 if order.customer.fidelity >= 1000 else 0 | |
@register_promotion | |
def bulk_item_promo(order): | |
"""10% discount for each LineItem with 20 or more units""" | |
discount = 0 | |
for item in order.cart: | |
if item.quantity >= 20: | |
discount += item.total() * .1 | |
return discount | |
@register_promotion | |
def large_order_promo(order): | |
"""7% discount for orders with 10 or more distinct items""" | |
distinct_items = {item.product for item in order.cart} | |
if len(distinct_items) >= 10: | |
return order.total() * .07 | |
return 0 | |
# BEGIN STRATEGY_BEST | |
def best_promo(order): # <2> | |
"""Select best discount available | |
""" | |
return max(promo(order) for promo in PROMOS) # <3> | |
# END STRATEGY_BEST |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment