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

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

(2024.04.21 Sun @KLN)

Case 1: Crypto

Crypto的自動(dòng)交易系統(tǒng)中,設(shè)置一個(gè)應(yīng)用類對(duì)接客戶端,根據(jù)不同的情況使用不同的銷售策略。銷售接口類包含方法sell_crypto,該案例中實(shí)現(xiàn)三種不同的銷售策略。

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

運(yùn)行結(jié)果

>>> 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

第二步,實(shí)現(xiàn)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.")

第三部,創(chuàng)建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維護(hù)了一個(gè)對(duì)策略的引用,允許用戶通過設(shè)定在不同的策略中做切換與選擇
  • strategy/策略:strategy interface/abstract class聲明了一個(gè)或多個(gè)方法,用于定義被使用的算法
  • concrete strategies/具體策略:具體策略實(shí)現(xiàn)了strategy interface,提供了算法的具體實(shí)現(xiàn)

優(yōu)缺點(diǎn)、適用場(chǎng)景

優(yōu)點(diǎn)

  • 符合Open/Close principle:不改變客戶端/context class代碼,就可引入新策略
  • 符合Isolation:不同算法的具體實(shí)現(xiàn)細(xì)節(jié)保持獨(dú)立,不影響彼此
  • Encapsulation:不同算法的具體實(shí)現(xiàn)內(nèi)容被完整封裝在策略類中,修改時(shí)不會(huì)影響context class。
  • run-time switching/運(yùn)行時(shí)切換:應(yīng)用或用戶可在運(yùn)行時(shí)切換策略

缺點(diǎn)

  • 創(chuàng)建額外對(duì)象:多數(shù)情況下需要使用策略對(duì)象設(shè)置context對(duì)象,所以需要?jiǎng)?chuàng)建和維護(hù)兩個(gè)對(duì)象
  • awareness among clients:用戶需要知道不同策略的差別方可選擇最佳策略
  • 提升復(fù)雜度:隨著應(yīng)用場(chǎng)景越來越復(fù)雜,會(huì)有越來越多的策略需要?jiǎng)?chuàng)建和維護(hù)

場(chǎng)景

  • 相似案例:相似的類,僅僅在執(zhí)行方式上有差別
  • 需要隔離:需要在業(yè)務(wù)邏輯與算法實(shí)現(xiàn)之間實(shí)現(xiàn)隔離

Reference

1 levelup點(diǎn)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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容