1. 程式人生 > >第6章 使用一等函式實現設計模式

第6章 使用一等函式實現設計模式

本章將使用函式物件重構“策略”模式,還將討論一種更簡單的方式,用於簡化“命令”模式。 6.1 案例分析:重構“策略”模式 《設計模式:可複用面向物件軟體的基礎》一書是這樣概括“策略”模式的:     定義一系列演算法,把它們一一封裝起來,並且使它們可以互相替換。本模式使得演算法可以獨立於使用它的客戶而變化。 電商領域有一個經典的“策略”模式,根據客戶的屬性或訂單中的商品計算折扣。下圖的UML類圖指出了“策略”模式對類的編排: 假如一個網店指定了下述折扣規則:
  • 有1000或以上積分的顧客,每個訂單享5%折扣。
  • 同一訂單中,單個商品的數量達到20個或以上,享10%折扣。
  • 訂單中的不同商品達到10個或以上,享7%折扣。
根據“策略”模式的UML類圖,其中涉及下列內容: 上下文      把一些計算委託給實現不同演算法的可互換元件,它提供服務。在這個例子中,上下文是Order,它會根據不同的演算法計算促銷折扣。 策略      實現不同演算法的元件共同的介面。在這個例子中,Promotion的抽象類扮演這個角色。 具體策略      “策略”的具體子類。fidelityPromo、BulkPromo和LargeOrderPromo是這裡實現的三個具體策略。 子類化      首先,定義一個抽象基類的“策略”;然後,在這個抽象基類基礎上,子類化不同的“策略”。(程式碼見附件classic_strategy.py)
使用函式實現“策略”模式
     將具體策略用函式實現,去掉抽象基類。(程式碼見附件strategy.py)      優點:函式實現比子類化,減少程式碼量,避免了使用相同策略時不斷新建具體策略物件,減少消耗。 選擇最佳策略:簡單的方式      使用函式列表計算出折扣額度最大的。(程式碼見附件strategy_best.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()      返回一個字典,表示當前的全域性符號表,這個符號表始終針對當前模組。 #內省模組的全域性名稱空間,構建promos列表  (程式碼見附件strategy_best2.py)
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 本章小結 ***