Python3面向对象——案例-01
经典的策略模式案例
问题描述
使用“策略”设计模式处理订单折扣的 UML 类图

定义一系列算法,把它们一一封装起来,并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。
电商领域有个功能明显可以使用“策略”模式,即根据客户的属性或订单中的商品计算折扣。
假如一个网店制定了下述折扣规则,每个订单只能享用一个折扣:
- Customers with 1,000 or more fidelity points get a global 5% discount per order.
- A 10% discount is applied to each line item with 20 or more units in the same order.
- Orders with at least 10 distinct items get a 7% global discount.
content
把一些计算委托给实现不同算法的可互换组件,它提供服务。在这个电商示例中,上下文是 Order,它会根据不同的算法计算促销折扣。
strategy
实现不同算法的组件共同的接口。在这个示例中,名为 Promotion 的抽象类扮演这个角色。
concrete strategy
“策略”的具体子类。fidelityPromo、BulkPromo 和 LargeOrderPromo 是这里实现的三个具体策略。
问题解决代码
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 = '<Order total: {:.2f} due: {:.2f}>'
return fmt.format(self.total(), self.due())
#--------------------------------------------------------
class Promotion(ABC): # the Strategy: an abstract base class
@abstractmethod
def discount(self, order):
"""Return discount as a positive dollar amount"""
#--------------------------------------------------------
class FidelityPromo(Promotion): # first Concrete Strategy
"""5% discount for customers with 1000 or more fidelity points"""
def discount(self, order):
return order.total() * .05 if order.customer.fidelity >= 1000 else 0
#--------------------------------------------------------
class BulkItemPromo(Promotion): # second Concrete Strategy
"""10% discount for each LineItem with 20 or more units"""
def discount(self, order):
discount = 0
for item in order.cart:
if item.quantity >= 20:
discount += item.total() * .1
return discount
#--------------------------------------------------------
class LargeOrderPromo(Promotion): # third Concrete Strategy
"""7% discount for orders with 10 or more distinct items"""
def discount(self, order):
distinct_items = {item.product for item in order.cart}
if len(distinct_items) >= 10:
return order.total() * .07
return 0
# 两个顾客:joe 的积分是 0,ann 的积分是 1100。
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)]
# fidelityPromo 没给 joe 提供折扣
Order(joe, cart, FidelityPromo())
<Order total: 42.00 due: 42.00>
# ann 得到了 5% 折扣,因为她的积分超过 1000
Order(ann, cart, FidelityPromo())
<Order total: 42.00 due: 39.90>
# banana_cart 中有 30 把香蕉和 10 个苹果
banana_cart = [LineItem('banana', 30, .5),
LineItem('apple', 10, 1.5)]
# BulkItemPromo 为 joe 购买的香蕉优惠了 1.50 美元
Order(joe, banana_cart, BulkItemPromo())
<Order total: 30.00 due: 28.50>
# long_order 中有 10 个不同的商品,每个商品的价格为 1.00 美元
long_order = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)]
# LargerOrderPromo 为 joe 的整个订单提供了 7% 折扣
Order(joe, long_order, LargeOrderPromo())
<Order total: 10.00 due: 9.30>
Order(joe, cart, LargeOrderPromo())
<Order total: 42.00 due: 42.00>
案例来自《Fluent Python》Luciano Ramalho著
Python3面向对象——案例-01的更多相关文章
- python 面向对象编程案例01
# -*- coding: utf-8 -*- #python 27 #xiaodeng #面向对象编程案例01 class Behave(): def __init__(self,name): se ...
- java基础学习05(面向对象基础01)
面向对象基础01 1.理解面向对象的概念 2.掌握类与对象的概念3.掌握类的封装性4.掌握类构造方法的使用 实现的目标 1.类与对象的关系.定义.使用 2.对象的创建格式,可以创建多个对象3.对象的内 ...
- web综合案例01
web综合案例01 ... .... 内容待添加
- python022 Python3 面向对象
Python3 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触 ...
- 面向对象案例-学生信息管理系统V0.6
更新版本 面向对象案例 - 学生信息管理系统V1.0 项目要求: 实体类: 学生类: id, 姓名,年龄,性别,成绩 需要使用数组保存学生信息 Student[] allStu 需要完成的方法 1. ...
- 081 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 06 new关键字
081 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 06 new关键字 本文知识点:new关键字 说明:因为时间紧张,本人写博客过程中只是 ...
- 080 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 05 单一职责原则
080 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 05 单一职责原则 本文知识点:单一职责原则 说明:因为时间紧张,本人写博客过程中只是 ...
- 079 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 04 实例化对象
079 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 04 实例化对象 本文知识点:实例化对象 说明:因为时间紧张,本人写博客过程中只是对知 ...
- 078 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 03 创建类
078 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 03 创建类 本文知识点:创建类 说明:因为时间紧张,本人写博客过程中只是对知识点的关 ...
随机推荐
- notepad++64位添加plugin manager
- 64位的notepad++,下载下来似乎没有plugin manager,如果真没有可以下载plugin manager. - plugin manager的下载地址:https://github ...
- 如何判断mac地址时multicast还是broadcast ?
ethernet 的地址其实就是mac地址,长度为6 byte,其中有一位为 multicast bit 位. 当unicast/multicast bit 位置1时就是 multicast,mac ...
- FreeSWITCH Git版本管理
由于测试FreeSWITCH不同版本的需要,研究了下Git的使用,通过Git来管理所有的版本,方便了测试.以下就总结下具体的使用方法: 其中:git clone ..是现在git仓库:git tag ...
- cocos creator 的scorllview 滑动事件和 子内容触摸事件会产生冲突
1:问题描叙: UI上的 scorllview 的子元素需要拖动到游戏场景.所以子元素需要绑定触摸事件,scorllview 默认的事件处理方式就会和子元素的触摸事件冲突.2:解决方案: Scroll ...
- as 插件GsonFormat用法(json字符串快速生成javabean)
GsonFormat 主要用于使用Gson库将JSONObject格式的String 解析成实体,该插件可以加快开发进度,使用非常方便,效率高. 插件地址:https://plugins.jetbra ...
- linux java报错汇总
一:♦linux 下javac 编译报 需要class, interface 或enum错误 ♦解析时已到达文件结尾 原因:大括号补匹配 //注意看报警提示
- python----线程进程协程
python线程: import threading import time def show(arg): time.sleep() print('thread' + str(arg)) ): t = ...
- 线段树解LIS
先是nlogn的LIS解法 /* LIS nlogn解法 */ #include<iostream> #include<cstring> #include<cstdio& ...
- hdu4942线段树模拟rotate操作+中序遍历 回头再做
很有意思的题目,详细题解看这里 https://blog.csdn.net/qian99/article/details/38536559 自己的代码不知道哪里出了点问题 /* rotate操作不会改 ...
- Python 3 官方文档学习(1)
本文系官方文档翻译之作,不当之处,敬请原谅! range()函数 如果需要遍历一个数字序列,可以使用内置的range函数.该函数会生成等差序列. 1 2 3 range(5)# 范围[0, 5) ra ...