第6章 使用一等函式實現設計模式
阿新 • • 發佈:2019-02-15
本章將使用函式物件重構“策略”模式,還將討論一種更簡單的方式,用於簡化“命令”模式。
6.1 案例分析:重構“策略”模式
《設計模式:可複用面向物件軟體的基礎》一書是這樣概括“策略”模式的:
定義一系列演算法,把它們一一封裝起來,並且使它們可以互相替換。本模式使得演算法可以獨立於使用它的客戶而變化。
電商領域有一個經典的“策略”模式,根據客戶的屬性或訂單中的商品計算折扣。下圖的UML類圖指出了“策略”模式對類的編排:
假如一個網店指定了下述折扣規則:
使用函式實現“策略”模式
將具體策略用函式實現,去掉抽象基類。(程式碼見附件strategy.py)
優點:函式實現比子類化,減少程式碼量,避免了使用相同策略時不斷新建具體策略物件,減少消耗。
選擇最佳策略:簡單的方式
使用函式列表計算出折扣額度最大的。(程式碼見附件strategy_best.py)
- 有1000或以上積分的顧客,每個訂單享5%折扣。
- 同一訂單中,單個商品的數量達到20個或以上,享10%折扣。
- 訂單中的不同商品達到10個或以上,享7%折扣。
使用函式實現“策略”模式
缺點:若想新增新的促銷策略,要定義相應的函式,還要記得把它新增到promos列表中;否則,計算最佳策略時不會考慮它。 找出模組中的全部策略 globals() 返回一個字典,表示當前的全域性符號表,這個符號表始終針對當前模組。 #內省模組的全域性名稱空間,構建promos列表 (程式碼見附件strategy_best2.py)promos = [fidelity_promo, bulk_item_promo, large_order_promo] def best_promo(order): """Select best discount available """ return max(promo(order) for promo in promos)
promos = [globals()[name] for name in globals() # <1> 迭代globals()返回字典中的各個name
if name.endswith('_promo') # <2> 只選擇以_promo結尾的名稱
and name != 'best_promo'] # <3> 過濾掉best_promo自身,防止無限遞迴
def best_promo(order):
"""Select best discount available
"""
return max(promo(order) for promo in promos)
#內省單獨的promotions模組,構建promos列表(程式碼見附件strategy_best3.py和promotions.py)
promos = [func for name, func in
inspect.getmembers(promotions, inspect.isfunction)]
def best_promo(order):
"""Select best discount available
"""
return max(promo(order) for promo in promos)
inspect.getmembers函式用於獲取物件的屬性,第二個引數是可選的判斷條件。我們使用的是inspect.isfunction,只獲取模組中的函式。
promotions模組存放各種具體策略。
6.2 “命令”模式
***
6.3 本章小結
***