策略模式Strategy Pattern, 2024-04-21

(2024.05.01 Wed @KLN)
策略模式是行為模式的一種,定義了一族算法/策略,每種策略封裝(encapsulate)在其自身的類中。這些策略實現相似的功能,但存在一定程度的差別。如果不使用設計模式,這些策略往往導致if-else的大量使用。策略模式允許所有算法和策略可互相取代(interchangeable),使用戶可以在運行代碼時根據需求不同選擇不同的策略并且不需要更改代碼。

(2024.04.21 Sun @KLN)

Case 1: Crypto

Crypto的自動交易系統中,設置一個應用類對接客戶端,根據不同的情況使用不同的銷售策略。銷售接口類包含方法sell_crypto,該案例中實現三種不同的銷售策略。

from abc import ABC, abstractmethod


class SellStrategy(ABC):
    """ it sells BTC and buys USDT """
    @abstractmethod
    def sell_crypto(self, balance: float, currency: float) -> dict:
        """sells crypto and returns new balance"""
        

class SellAll(SellStrategy):
    def sell_crypto(self, balance: float, currency: float) -> dict:
        """critical!! Market doesn't look nice. Sell!"""
        btc = 0
        usdt = balance * currency
        return {"btc":btc, "usdt": usdt}
    

class SellHalf(SellStrategy):
    def sell_crypto(self, balance: float, currency: float) -> dict:
        """ cautious! let's sell half and wait! """
        btc = balance / 2
        usdt = (balance / 2) * currency
        return {"btc":btc, "usdt": usdt}
    

class SellLittle(SellStrategy):
    def sell_crypto(self, balance: float, currency: float) -> dict:
        """ HODL! """
        btc = balance * 0.9
        usdt = (balance * 0.1) * currency
        return {"btc":btc, "usdt": usdt}
    

class TradingApp:
    assets = {"btc":100,"usdt":0}
    currency = 30000
    def sell_order(self, sell_decision: SellStrategy):
        self.assets = sell_decision.sell_crypto(self.assets["btc"], self.currency)
        return self.assetsfrom abc import ABC, abstractmethod

運行結果

>>> A = TradingApp()
>>> assets = A.sell_order(SellLittle())
>>> print(assets)
{'btc': 90.0, 'usdt': 300000.0}
>>> assets = A.sell_order(SellHalf())
>>> print(assets)
{'btc': 45.0, 'usdt': 1350000.0}

Case 2: Payment Strategy

(2024.05.01 Wed @KLN)
使用不同支付方式支付。

首先定義strategy interface (abstract class)

from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

第二步,實現concrete strategies

class CreditCardPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"Paid {amount} using Credit Card.")


class PayPalPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"Paid {amount} using PayPal.")


class BankTransferPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"Paid {amount} using PayPal.")

第三部,創建context class

class PaymentContext:
    def __init__(self, payment_strategy):
        self.payment_strategy = payment_strategy

    def set_payment_strategy(self, payment_strategy):
        self.payment_strategy = payment_strategy

    def make_payment(self, amount):
        self.payment_strategy.pay(amount)

第四步,使用strategy pattern

if __name__ == "__main__":
    credit_card = CreditCardPayment()
    paypal = PaPalPayment()
    bank_transfer = BankTransferPayment()
    payment_context = PaymentContext()

    payment_context.set_payment_strategy(credit_card)
    payment_context.make_payment(99)  # 使用信用卡支付99
    
    payment_context.set_payment_strategy(paypal)
    payment_context.make_paymet(100)  # 使用paypal支付100
 
    payment_context.set_payment_strategy(bank_transfer)
    payment_context.make_payment(101)  # 使用bank transfer支付101

通過該案例回顧策略模式的基本元素

  • context/前后文:context class維護了一個對策略的引用,允許用戶通過設定在不同的策略中做切換與選擇
  • strategy/策略:strategy interface/abstract class聲明了一個或多個方法,用于定義被使用的算法
  • concrete strategies/具體策略:具體策略實現了strategy interface,提供了算法的具體實現

優缺點、適用場景

優點

  • 符合Open/Close principle:不改變客戶端/context class代碼,就可引入新策略
  • 符合Isolation:不同算法的具體實現細節保持獨立,不影響彼此
  • Encapsulation:不同算法的具體實現內容被完整封裝在策略類中,修改時不會影響context class。
  • run-time switching/運行時切換:應用或用戶可在運行時切換策略

缺點

  • 創建額外對象:多數情況下需要使用策略對象設置context對象,所以需要創建和維護兩個對象
  • awareness among clients:用戶需要知道不同策略的差別方可選擇最佳策略
  • 提升復雜度:隨著應用場景越來越復雜,會有越來越多的策略需要創建和維護

場景

  • 相似案例:相似的類,僅僅在執行方式上有差別
  • 需要隔離:需要在業務邏輯與算法實現之間實現隔離

Reference

1 levelup點gitconnected, Design Patterns in Python: Strategy Pattern, Okan Yenigun
2 medium, Exploring the Strategy Design Pattern in Python: A Guide with Examples, Nitesh Bhargav
3 geeksforgeeks

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容