Python策略模式实例

一 策略模式

完成一件事通常有很多种方式,每一种方式都是一个策略。

策略模式(Strategy)定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。

经典的策略模式由三部分组成:

  • Context:上下文环境类
  • Stragety:策略基类
  • ConcreteStragety:具体策略

Context用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用;Strategy是策略类,用于定义所有支持算法的公共接口;ConcreteStrategy是具体策略类,封装了具体的算法或行为,继承于Strategy。

UML结构图如下:

 二 策略模式的优缺点

     优点

  • 算法可以自由切换
  • 避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
  • 扩展性良好,增加一个策略只需实现接口即可

   缺点

  • 策略类数量会增多,每个策略都是一个类,复用的可能性很小
  • 所有的策略类都需要对外暴露

三 策略模式的示例

以超市优惠打折的三种策略为例,演示策略模式:

策略模式的三部分对应示例中的类如下:

  • Context:Order类
  • Stragety:Promotion类
  • ConcreteStragety:BonusPointPromo、BulkPromo、LargeOrderPromo类

一些例子中用到的别的类:

class Item(object):
    '''商品类 :商品种类、价格、数量,该商品的总价'''
    def __init__(self,issue, price, quantity):
        self.issue = issue
        self.price = price
        self.quantity = quantity

    def itemtotal(self):  #返回购买该商品的总价
        return self.price * self.quantity


class Customer(object):
    '''顾客类 :顾客名字、顾客的积分'''
    def __init__(self, name ,bonuspoint):
        self.name = name
        self.bonuspoint = bonuspoint
        

Context:Order类

class Order(object):
    '''订单类:顾客(主要用来查看其原始积分情况)、选择的优惠方案'''
    def __init__(self, customer, promotion=None):
        self.cart = []
        self.customer = customer
        self.promotion = promotion

    def add_to_cart(self, *items):  #加入购物车方法,传入不定长的Item类实例
        for item in items:
            self.cart.append(item)

    def total(self):    #计算订单的总价 为每种商品的总价和
        total = 0
        for item in self.cart:
            total += item.itemtotal()
        return total

    def pay(self):  #计算该订单需要实际出的钱
        if not self.promotion:  #如果没有优惠促销活动 那么折扣为0
            discount = 0
        else:
            discount  = self.promotion.discount(self) #有的话 计算折扣
        payment = self.total() - discount  #payment为最后需要付的钱
        print(f'折扣策略{type(self.promotion).__name__}:原价{self.total()},折扣价: {payment}')
        return payment

 Stragety:Promotion类

from abc import ABC, abstractmethod

class Promotion(ABC):
    @abstractmethod     #定义抽象方法,子类必须重写discount方法
    def discount(self, order):
        pass

这里介绍一下上述用到的@abstractmethod的用法:

由于python 没有抽象类、接口的概念,所以要实现这种功能得abc.py 这个类库。

@abstractmethod:抽象方法,含abstractmethod方法的类不能实例化,继承了含abstractmethod方法的子类必须复写所有abstractmethod装饰的方法,未被装饰的可以不重写。

ConcreteStragety:BonusPointPromo、BulkPromo、LargeOrderPromo类

class BonusPointPromo(Promotion):  #积分兑换的优惠策略,继承Promotion类
    '''
    积分满1000分,可以兑换20元现金券。该方法不能与别的优惠方案叠加使用
    '''
    def discount(self, order):
        return 20 if order.customer.bonuspoint >=1000 else 0


class BulkPromo(Promotion):   #大宗购买的优惠策略,继承Promotion类
    '''
    商品总数购买10件,总订单可打9折。该方法不能与别的优惠方案叠加使用
    '''
    def discount(self, order):
        discount = 0
        totalQuantity=0
        for item in order.cart:
            totalQuantity += item.quantity
        if totalQuantity >= 10:
            discount = order.total() * 0.1
            
        return discount


class LargeOrderPromo(Promotion):  #高额订单的优惠策略,继承Promotion类
    '''
    订单总金额大于等于500元,立减50元
    '''
    def discount(self, order):
        discount = 0
        if order.total() >= 500:
            discount = 50

        return discount

 测试

if __name__ == '__main__':
    
    ZhangSan = Customer('张三',1200)  #有1200积分的张三去超市买东西
    item1 = Item('卫生纸', 20, 10)
    item2 = Item('玩偶', 100, 2)
    item3 = Item('牛奶', 50, 4)
    
    order = Order(ZhangSan, BonusPointPromo())
    order.add_to_cart(item1, item2, item3)
    pay1 = order.pay()
    
    order = Order(ZhangSan, BulkPromo())
    order.add_to_cart(item1, item2, item3)
    pay2 = order.pay()
    
    order = Order(ZhangSan, LargeOrderPromo())
    order.add_to_cart(item1, item2, item3)
    pay3 = order.pay()

结果如下: 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值