[DP]strategy

来源:互联网 发布:mac final cutpro x 编辑:程序博客网 时间:2024/06/05 15:28

# coding: utf-8# # Srategy Pattern# 策略模式定义一系列算法并封装它们,这些算法可以互换。# 策略模式还根据不同的对象使用不同的算法。# ## class implement# In[10]:import abcimport collectionsCustomer = collections.namedtuple('Customer', 'name fidelity')class LineItem(object):    def __init__(self, product, quantity, price):        self.product = product        self.quantity = quantity        self.price = price        def total(self):        return self.quantity * self.price    class Order(object):    def __init__(self, customer, cart, promotion=None):        self.customer = customer        self.cart = cart        self.promotion = promotion        def total(self):        if not hasattr(self, '__total'):            self.__total = sum(lineitem.total() for lineitem in self.cart)        return self.__total        def due(self):        discount = 0 if self.promotion is None else self.promotion.discount(self)        return self.total() - discount        def __repr__(self):        return "<Order total:{:.2f} due:{:.2f}>".format(self.total(), self.due())class Promotion(abc.ABC):    """abstract class of Promotion"""    @abc.abstractmethod    def discount(self, Order):        """return the discount vary different Order """        pass    class FidelityPromo(Promotion):    """if fidelity >= 1000 Give 5% discount"""        def discount(self, order):        """ return 0.05 of the total price of Order """        return 0.05*order.total() if order.customer.fidelity >= 100 else 0.0class BulkItemPromo(Promotion):    """if the lineitem's quantity >= 20 give the lineitem'total price 10% discount"""    def discount(self, order):        discount = sum((0.1*lineitem.total() if lineitem.quantity >= 20 else 0.0 for lineitem in order.cart))        return discount        class LargeOrderPromo(Promotion):    """7% discount for the kind of lineitems in cart >10 """    def discount(self, order):        kinds = {lineitem.product for lineitem in order.cart}        return 0.07*order.total() if len(kinds)>=10 else 0.0                # In[3]:joe = Customer('John Doe', 0)# In[4]:ann = Customer('Ann Smith', 1100)# In[5]:cart = [LineItem('banana', 4, .5),LineItem('apple', 10, 1.5),LineItem('watermellon', 5, 5.0)]# In[11]:Order(joe, cart, FidelityPromo()) # joe's fidelity < 1000# Out[11]: <Order total:42.00 due:42.00># In[12]:Order(ann, cart, FidelityPromo()) # ann's fidelity > 1000# Out[12]: <Order total:42.00 due:39.90># In[13]:banana_cart = [LineItem('banana', 30, .5),LineItem('apple', 10, 1.5)]# In[14]:Order(joe, banana_cart, BulkItemPromo()) # number of 'banana' > 20# Out[14]: <Order total:30.00 due:28.50># In[15]:long_order = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)]# In[16]:Order(joe, long_order, LargeOrderPromo()) # number of line items >=10# Out[16]: <Order total:10.00 due:9.30># In[17]:Order(joe, cart, LargeOrderPromo())# Out[17]: <Order total:42.00 due:42.00># ## function implement# function is the first class in python.# considering the subclasses of Promotion are very simple, i think implementation them as function is better.# the defination of Customer, LineItem and Oder is no need to change.# but change the due method in Oder is nesscery.# In[18]:import collectionsCustomer = collections.namedtuple('Customer', 'name fidelity')class LineItem(object):    def __init__(self, product, quantity, price):        self.product = product        self.quantity = quantity        self.price = price        def total(self):        return self.quantity * self.price    class Order(object):    def __init__(self, customer, cart, promotion=None):        self.customer = customer        self.cart = cart        self.promotion = promotion        def total(self):        if not hasattr(self, '__total'):            self.__total = sum(lineitem.total() for lineitem in self.cart)        return self.__total        def due(self):        discount = 0 if self.promotion is None else self.promotion(self)        return self.total() - discount        def __repr__(self):        return "<Order total:{:.2f} due:{:.2f}>".format(self.total(), self.due())def fidelity_promo(order):    return 0.05*order.total() if order.customer.fidelity >= 100 else 0.0def bulk_promo(order):    return sum((0.1*lineitem.total() if lineitem.quantity >= 20 else 0.0 for lineitem in order.cart))def large_order_promo(order):    kinds = {lineitem.product for lineitem in order.cart}    return 0.07*order.total() if len(kinds)>=10 else 0.0# In[19]: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)]# In[20]:Order(joe, cart, fidelity_promo) # joe's fidelity < 1000# Out[20]: <Order total:42.00 due:42.00># In[21]:Order(ann, cart, fidelity_promo) # ann's fidelity > 1000# Out[21]:<Order total:42.00 due:39.90># In[22]:banana_cart = [LineItem('banana', 30, .5),LineItem('apple', 10, 1.5)]# In[24]:Order(joe, banana_cart, bulk_promo) # number of 'banana' > 20# Out[24]: <Order total:30.00 due:28.50># In[25]:long_order = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)]# In[27]:Order(joe, long_order, large_order_promo) # number of line items >=10# Out[27]:<Order total:10.00 due:9.30># In[28]:Order(joe, cart, large_order_promo)# Out[28]: <Order total:42.00 due:42.00># ##  what is the best promotion# In[31]:promos = [fidelity_promo, bulk_promo, large_order_promo]def best_promo(order):    return max(promo(order) for promo in promos)# In[32]:Order(joe, long_order, best_promo)# Out[32]:<Order total:10.00 due:9.30># In[33]:Order(joe, banana_cart, best_promo)# Out[33]: <Order total:30.00 due:28.50># In[34]:Order(ann, cart, best_promo)# Out[34]:<Order total:42.00 due:39.90># there is another way to find the all promotions in a module.# use globals()# globals() return a dict of all parameters: variable, function , class in current module.# In[35]:promos = [globals()[name] for name in globals() if name.endswith('_promo') and name != 'best_promo']# also inspect module can inpect a module.# for example, there is a module named promotions:# In[ ]:promos = [func for name, func in inspect.getmembers(promotions, inspect.isfunction)]






0 0
原创粉丝点击