6. Design Patterns with First-Class Functions
1. Refactoring Strategy
1.1 Classic Strategy
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 # obj
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): # an abstract base class
@abstractmethod
def discount(self, order): # 返回折扣的总钱数
pass class FidelityPromo(Promotion):
"""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):
"""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):
"""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 = Customer('John Doe', 1000)
cart = [LineItem('banana', 4, .5), LineItem('apple', 25, 1.5), LineItem('watermellon', 5, 5.0)]
print(Order(joe, cart, FidelityPromo())) # <Order total: 64.50 due: 61.27>
print(Order(joe, cart, BulkItemPromo())) # <Order total: 64.50 due: 60.75>
print(Order(joe, cart, LargeOrderPromo())) # <Order total: 64.50 due: 64.50>
1.2 Function-Oriented Strategy
- A flyweight is a shared object that can be used in multiple contexts simultaneously. (享元)
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 # obj
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): # created just once
"""5% discount for customers with 1000 or more fidelity points"""
return order.total() * .05 if order.customer.fidelity >= 1000 else 0 def bulk_item_promo(order):
"""10% discount for each LineItem with 20 or more units"""
discount = 0
for item in order.cart:
if item.quantity >= 20:
discount += item.total() * .1
return discount def large_order_promo(order):
"""7% discount for orders with 10 or more distinct items"""
distinct_items = {item.product for item in order.cart}
if len(distinct_items) >= 10:
return order.total() * .07
return 0 joe = Customer('John Doe', 1000)
cart = [LineItem('banana', 4, .5), LineItem('apple', 25, 1.5), LineItem('watermellon', 5, 5.0)]
print(Order(joe, cart, fidelity_promo)) # <Order total: 64.50 due: 61.27>
print(Order(joe, cart, bulk_item_promo)) # <Order total: 64.50 due: 60.75>
print(Order(joe, cart, large_order_promo)) # <Order total: 64.50 due: 64.50>
1.3 Choosing the Best Strategy
promos = [fidelity_promo, bulk_item_promo, large_order_promo]
# promos = [globals()[name] for name in globals() if name.endswith('_promo') and name != 'best_promo']
# import inspect
# promos = [func for name, func in inspect.getmembers(promotions, inspect.isfunction)] # promotions为自定模块
def best_promo(order):
"""Select best discount available"""
return max(promo(order) for promo in promos)
promos = []
def promotion(promo_func):
promos.append(promo_func)
return promo_func @promotion
def fidelity_promo(order): # created just once
"""5% discount for customers with 1000 or more fidelity points"""
return order.total() * .05 if order.customer.fidelity >= 1000 else 0 @promotion
def bulk_item_promo(order):
"""10% discount for each LineItem with 20 or more units"""
discount = 0
for item in order.cart:
if item.quantity >= 20:
discount += item.total() * .1
return discount @promotion
def large_order_promo(order):
"""7% discount for orders with 10 or more distinct items"""
distinct_items = {item.product for item in order.cart}
if len(distinct_items) >= 10:
return order.total() * .07
return 0
2. Command
6. Design Patterns with First-Class Functions的更多相关文章
- Learning JavaScript Design Patterns The Module Pattern
The Module Pattern Modules Modules are an integral piece of any robust application's architecture an ...
- Design Patterns Example Code (in C++)
Overview Design patterns are ways to reuse design solutions that other software developers have crea ...
- Massive Collection Of Design Patterns, Frameworks, Components, And Language Features For Delphi
Developer beNative over on GitHub has a project called Concepts which is a massive collection of Del ...
- Design Patterns Simplified - Part 3 (Simple Factory)【设计模式简述--第三部分(简单工厂)】
原文链接:http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part3-factory/ Design ...
- Design Patterns Simplified - Part 2 (Singleton)【设计模式简述--第二部分(单例模式)】
原文链接: http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part-2-singleton/ De ...
- Head First Design Patterns
From Head First Design Patterns. Design Principle: Idnetify the aspects of your application that var ...
- Apex Design Patterns
Apex allows you to build just about any custom solution on the Force.com platform. But what are the ...
- [Design Patterns] 4. Creation Pattern
设计模式是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结,使用设计模式的目的是提高代码的可重用性,让代码更容易被他人理解,并保证代码可靠性.它是代码编制真正实现工程化. 四个关键元素 ...
- [Design Patterns] 3. Software Pattern Overview
When you're on the way which is unknown and dangerous, just follow your mind and steer the boat. 软件模 ...
- [Design Patterns] 1. Primary concept & term - UML
It's time to review design patterns, especially when I reach the turning-point of my career. That's ...
随机推荐
- Flutter 异步Future与FutureBuilder实用技巧
什么是Future? Future表示在接下来的某个时间的值或错误,借助Future我们可以在Flutter实现异步操作.它类似于ES6中的Promise,提供then和catchError的链式调用 ...
- ES6、ES7、ES8、ES9、ES10
ES6新特性(2015) ES6的特性比较多,在 ES5 发布近 6 年(2009-11 至 2015-6)之后才将其标准化.两个发布版本之间时间跨度很大,所以ES6中的特性比较多.在这里列举几个常用 ...
- Java基础——值传递
值传递? 参数传递的值的拷贝,改变拷贝不影响原参数. 引用传递? 参数传递的是参数本身,改变形参,实参也改变. Java中是什么传递? Java中只有值传递 实际情况为什么不对呢? 1. 基本数据类型 ...
- c++学习笔记_5
前言:本笔记所对应的课程为中国大学mooc中北京大学的程序设计与算法(三)C++面向对象程序设计,主要供自己复习使用,且本笔记建立在会使用c和java的基础上,只针对与c和java的不同来写 继承 继 ...
- redis的安装和连接
- 磁盘分区知识与linux系统分区实践
一.磁盘存储逻辑结构图 回忆: (1)什么是分区? 磁盘分区就相当于给磁盘打隔断. (2)磁盘在linux里的命名 IDE /dev/hda hdb SCSI sda sdb 分区 ...
- [CF306C]White, Black and White Again_排列组合
White, Black and White Again 题目链接:https://www.luogu.org/problem/CF306C 数据范围:略. 题解: 记得不要看错题,容易看成来回交替下 ...
- [转帖]Linux-Windows 端口转发 netsh 还有 rinetd
Linux-Windows 端口转发 https://www.cnblogs.com/operationhome/p/11284559.html 之前自己学习过 netsh 也曾经用过frp 这次学习 ...
- [OpenBenchMarking] AMD CPU 的性能简单对比
来源: https://openbenchmarking.org/result/1710193-AL-EPYC7351P64 1. 2. 3. 4.
- 一个包含python和java环境的dockerfile
现在一个项目中遇到python调用java的jar包的环境.为了方便发布,编写了这个dockerfile,作为基础镜像. #this docker file is used to build runt ...