第6章:使用函数实现“策略模式”

本文介绍如何使用策略模式来实现电商系统的折扣计算功能,通过定义一系列算法并使其可互换,使得折扣策略能够独立于系统其他部分灵活调整。文章详细解释了三种不同的折扣策略,并展示了如何在订单中应用这些策略。

策略模式是定义一系列算法,把它们一一封装起来,并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。

电商系统有个功能明显的可以使用"策略"模式,即根据用户的属性或订单中的商品数量计算折扣。
假如一个网店制定了一下的折扣规则:

  1. 有 1000 积分或以上的用户,每个订单享受 5% 的折扣;
  2. 同一个订单中,单个商品的数量达到20个及以上,享受 10% 的折扣;
  3. 订单中的不同商品达到10个及以上,享受 7% 的折扣;

简单起见,我们假设一个订单一次只能享受一个折扣;

# 使用函数实现策略模式,不使用抽象类;

from collections import namedtuple

# 客户类                             名称     积分
Customer = namedtuple('Customer', ['name', 'fidelity'])


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


# 实现 Order 类,支持插入式折扣策略:
class Order:  # 在"策略"模式中扮演上下文的角色
    """订单类"""

    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())


# 策略一:
def fidelity_promo(order: Order):
    """为 1000 及以上积分的客户提供 5% 的折扣"""
    return order.total() * 0.5 if order.customer.fidelity >= 1000 else 0


# 策略二:
def bulk_item_promo(order: Order):
    """订单中单个商品为 20 个及以上时,为该商品提供 10% 的折扣"""
    discount = 0
    for item in order.cart:
        if item.quantity >= 20:
            discount += item.total() * 0.1
    return discount


# 策略三:
def large_order_promo(order: Order):
    """订单中不同商品数量达到 10 个或以上时,提供 7% 的折扣"""
    distinct_items = {item.product for item in order.cart}
    if len(distinct_items) >= 10:
        return order.total() * 0.07
    return 0


# 策略列表
promos = [fidelity_promo, bulk_item_promo, large_order_promo]



def best_promo(order: Order):
    """选择可用的最佳策略"""
    # 返回各策略中最大的折扣金额
    return max(promo(order) for promo in promos)


if __name__ == '__main__':
    John = Customer('John', 1000)
    Jade = Customer('Jade', 1000)
    carts = [
        LineItem('香蕉', 4, 0.5),
        LineItem('苹果', 20, 15),
        LineItem('荔枝', 5, 5.0),
    ]

    print(Order(John, carts, best_promo))  # <Order total: 327.00 due: 163.50>

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值