• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

详解Python设计模式之策略模式

python 搞代码 4年前 (2022-01-09) 38次浏览 已收录 0个评论

虽然设计模式与语言无关,但这并不意味着每一个模式都能在每一门语言中使用。《设计模式:可复用面向对象软件的基础》一书中有 23 个模式,其中有 16 个在动态语言中“不见了,或者简化了”。

1、策略模式概述

策略模式:定义一系列本文来源gao($daima.com搞@代@#码(网算法,把它们一一封装起来,并且使它们之间可以相互替换。此模式让算法的变化不会影响到使用算法的客户。

电商领域有个使用“策略”模式的经典案例,即根据客户的属性或订单中的商品计算折扣。

假如一个网店制定了下述折扣规则。

  • 有 1000 或以上积分的顾客,每个订单享 5% 折扣。
  • 同一订单中,单个商品的数量达到 20 个或以上,享 10% 折扣。
  • 订单中的不同商品达到 10 个或以上,享 7% 折扣。

简单起见,我们假定一个订单一次只能享用一个折扣。

UML类图如下:

Promotion 抽象类提供了不同算法的公共接口,fidelityPromo、BulkPromo 和 LargeOrderPromo 三个子类实现具体的“策略”,具体策略由上下文类的客户选择。

在这个示例中,实例化订单(Order 类)之前,系统会以某种方式选择一种促销折扣策略,然后把它传给 Order 构造方法。具体怎么选择策略,不在这个模式的职责范围内。(选择策略可以使用工厂模式。)

2、传统方法实现策略模式:

from abc import ABC, abstractmethod
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


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.discount(self)
    return self.total() - discount

  def __repr__(self):
    fmt = '<订单 总价: {:.2f} 实付: {:.2f}>'
    return fmt.format(self.total(), self.due())


class Promotion(ABC): # 策略:抽象基类
  @abstractmethod
  def discount(self, order):
    """返回折扣金额(正值)"""


class FidelityPromo(Promotion): # 第一个具体策略
  """为积分为1000或以上的顾客提供5%折扣"""
  def discount(self, order):
    return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0


class BulkItemPromo(Promotion): # 第二个具体策略
  """单个商品为20个或以上时提供10%折扣"""
  def discount(self, order):
    discount = 0
    for item in order.cart:
      if item.quantity >= 20:
        discount += item.total() * 0.1
    return discount


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


joe = Customer('John Doe', 0)
ann = Customer('Ann Smith', 1100)

cart = [LineItem('banana', 4, 0.5),
    LineItem('apple', 10, 1.5),
    LineItem('watermellon', 5, 5.0)]

print('策略一:为积分为1000或以上的顾客提供5%折扣')
print(Order(joe, cart, FidelityPromo()))
print(Order(ann, cart, FidelityPromo()))

banana_cart = [LineItem('banana', 30, 0.5),
        LineItem('apple', 10, 1.5)]

print('策略二:单个商品为20个或以上时提供10%折扣')
print(Order(joe, banana_cart, BulkItemPromo()))

long_order = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)]

print('策略三:订单中的不同商品达到10个或以上时提供7%折扣')
print(Order(joe, long_order, LargeOrderPromo()))
print(Order(joe, cart, LargeOrderPromo()))

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:详解Python设计模式之策略模式

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址