• 流畅的python学习:策略模式


    经典策略模式

    # -*- coding:utf-8 -*-
    from abc import ABC, abstractmethod
    from collections import namedtuple
    
    Customer = namedtuple('Customer', 'name fidellty')
    
    class LineItem:
        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:
        def __init__(self, customer, cart, promotion=None):
            self.customer = customer
            # 传入的cart可能是生成器,转换成列表
            self.cart = list(cart)
            self.promotion = promotion
    
    
        def total(self):
            if not hasattr(self, '__total'):  # 如果类没有__total的属性,曾进行操作
                # 已经存在不重新计算?订单修改重新计算?
                # cart更新重新计算,不修改
                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.discount(self)
            return self.total() - discount
    
    
        # def max_due(self):
        #     promitions = [LargeOrderPromotion, BulkItemPromotion, FidelityPromotion]
        #     max_discount = {promition.__name__:promition().discount(self) for promition in promitions}
        #     print(max_discount)
        #     print(max_discount.get())
        #
        #     m = max(max_discount,key=max_discount.get())
        #     print(m)
        #     print('max discount=' + str(max_discount))
        #     return 'max discount!'
    
        def __repr__(self):
            fmt = '<Order total:{:.2f} due:{:.2f}>'
            return fmt.format(self.total(),self.due())
    
    class Promotion(ABC):
    
        @abstractmethod  # 抽象方法
        def discount(self, order):
            '''返回折扣金额正值'''
    
    
    class FidelityPromotion(Promotion):
        '''为1000积分以上的顾客提供5%的折扣'''
        def discount(self, order):
            return order.total() * 0.5 if  order.customer.fidellty >= 1000 else order.total()
    
    
    class BulkItemPromotion(Promotion):
        '''单个商品20个或以上的时提供10的折扣'''
        def discount(self, order):
            discount = 0
            for item in order.cart:
                if item.quantity >= 20:
                    discount += item.total() * .1
            return discount
    
    
    class LargeOrderPromotion(Promotion):
        '''订单中不同商品到达10个或以上时提供折扣7%'''
        a=3
        def __init__(self):
            pass
    
    
        def discount(self, order):
            # 集合去重复
            distinct_item = {item.product for item in order.cart}
            # print(distinct_item)
            # print(self.a)
            # print(order.cart)
            if len(distinct_item) >= 10:
                return order.total() * .07
            return 0
    
    
    
    
    
    
    # print(__name__ == "__main__")
    # print()
    if __name__ == "__main__":
        joe = Customer('John Doe', 1000)
        long_order = [LineItem(str(item), 20, 1.0) for item in range(10)]
        # max_promotion = max(discount() for discount in promition)
        o = Order(joe,long_order,LargeOrderPromotion())
        # print(o.max_due())
        o = Order(joe,long_order,LargeOrderPromotion())
        print(o)

    抽象一个类策略,用户传入到订单order中,对订单进行相应的优惠策略。

    每个类中都只有一个方法,可以考虑使用函数当做一等函数传入,进行代码简化

    一等函数改写经典策略模式

    # -*- coding:utf-8 -*-
    from collections import namedtuple
    
    
    Customer = namedtuple('Customer', 'name fidellty')
    class LineItem:
        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:
        def __init__(self, customer, cart, promotion=None):
            self.customer = customer
            # 传入的cart可能是生成器,转换成列表
            self.cart = list(cart)
            self.promotion = promotion
    
    
        def total(self):
            if not hasattr(self, '__total'):  # 如果类没有__total的属性,曾进行操作
                # 已经存在不重新计算?订单修改重新计算?
                # cart更新重新计算,不修改
                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())
    
    def FidelityPromotion(order):
        return order.total() * 0.5 if order.customer.fidellty>=1000  else 0
    
    
    def BulkItemPromotion(order):
        discount = 0
        for item in order.cart:
            if item.quantity >= 20:
                discount += item.total() * 0.1
        return discount
    
    def LargeOrderPromotion(order):
        distinct_item = {procduct for procduct in order.cart}
        if len(distinct_item) >=10:
            return order.total() * 0.07
        return order.total()
    
    if __name__ == "__main__":
        # max_promotion = max(discount() for discount in promition)
        joe = Customer('张三',50)
        long_order = [LineItem(str(item), 20, 1.0) for item in range(10)]
        o = Order(joe,long_order,LargeOrderPromotion)
        print(o)
        # print(o.max_due())
        o = Order(joe,long_order,BulkItemPromotion)
        print(o)
        o = Order(joe,long_order,FidelityPromotion)
        print(o)

    把函数当作对象传入到类内部,简化了代码,同时也简化了操作难度。可以更加便利的实现求最优策略

    def get_max_cheap(order):
        promotions = [FidelityPromotion, BulkItemPromotion, LargeOrderPromotion]
        max_discount = {promotion.__name__:Order(joe, long_order, promotion).due() for promotion in promotions}
        print(type(max_discount),max_discount)
        key_max = max(max_discount.keys(), key = (lambda k: max_discount[k]))
        key_min = min(max_discount.keys(), key = (lambda k: max_discount[k]))
        print("max promotion is %s,max values is %s" % (key_max, max_discount[key_max]))
        print("min promotion is %s,min values is %s" % (key_min, max_discount[key_min]))

    这样子操作有一个缺点,就是行数整个运行依托于列表promotions,如果有新的折扣函数,无法及时更新promotions列表。

    需要考虑,新增一个函数注册功能,把发现的函数新增到列表中

    promotions = []
    def regest(f):
        def in_re(*args,**kwargs):
            promotions.append(f)
            res = f(*args,**kwargs)
            return res
        return in_re

    编写装饰器,需要的参与最优计算得策略,都加上装饰器,使用装饰器完成注册,添加到列表promotions,有策略添加和删除,只需要加上相应的装饰器,即可完成注册

    此装饰器,可以简写成

    promotions = []
    def regest(f):
        promotions.append(f)
        return f

    在变体,添加参数,可以使装饰器可以支持方法注册及注销

    promotions = []
    def regest(res = True):
        def is_regest(f):
            if res:
                promotions.append(f)
            elif f in promotions:
                promotions.remove(f)
            return f
        return is_regest
  • 相关阅读:
    linux系统中将一列数据转换为若干列数据(列的顺序不变)
    linux系统中将矩形数据转换为一行、一列的形式
    linux系统中实现文本转置。
    linux shell 如何将多列数据变为一行数据
    linux系统中如何将一行数据变为一列
    bash: unlzma: command not found...
    linux系统中实现对行的批量替换
    linux系统中对指定行的字符串进行替换
    linux系统中对指定列的数据中的字符串进行替换
    linux系统中如何将每行特定数目字符后的字符替换为指定字符
  • 原文地址:https://www.cnblogs.com/zxw-xxcsl/p/12692345.html
Copyright © 2020-2023  润新知