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 ...
随机推荐
- 数据集成、变换、归约及相关MATLAB工具箱函数
数据预处理的主要内容包括数据清洗.数据集成.数据变换和数据规约,在数据挖掘的过程中,数据预处理工作量占到了整个过程的60%.数据清洗在上一篇博客中写过,这里主要写后面三部分. 数据集成 数据挖掘需要的 ...
- glide包管理工具
上一篇文章中我们已经成功的运行了go的代码,这是我们迈出的最基础的一步. 一个项目通常会依赖很多外部的库,当依赖的库比较多的时候,手工管理就会比较麻烦,这个时候就需要包管理工具出场了,帮你管理好所有依 ...
- mysql/mariadb数据库在插入表数据时,ID竟然成奇数增加了?看完下面内容就知道怎么处理了。
今天突然被问到一个问题,mysql数据库插入表数据时,设置了ID自增,但是插入数据后,ID却呈奇数增加,不是123456类型,而是13579形式,突然有点懵,研究了一会,发现是auto_increme ...
- appium(toast处理)
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expec ...
- sql注入02
第一关:基于错误的get单引号字符型注入 第二关:基于错误的get整形注入 第三关:基于错误的get单引号变形字符型注入 第四关:基础错误的双引号字符型注入 第五关: 第六关 第七关:导出文件get字 ...
- CImage 和 CvvImage 命名空间问题
[问题:名称CImage同时在两个库中出现] 1.出现: ATL #include <atlimage.h> OpenCv #include <highgui.h> #defi ...
- jquery清除元素的点击事件
$("#id").css("pointer-events", "none");
- golang语言sql Rows转化保存成map
func DoQuery(db *sql.DB, sqlInfo string, args ...interface{}) ([]map[string]interface{}, error) { ro ...
- shell备份脚本
#!/bin/bash #不存在的变量终止脚本执行 set -o nounset #执行出错终止脚本执行 set -o errexit #递归列出文件的绝对路径并执行压缩 delDir=`date - ...
- Python 解LeetCode:33. Search in Rotated Sorted Array
题目描述:在一个旋转数组中查找给定的值,其中旋转数组中不含重复值: 思路: 第一遍二分遍历,找到数组中最小值的索引: 第二遍分别对最小值左右两边的数组进行二分查找: class Solution(ob ...