Design Pattern Strategy

策略模式

將可互換的演算法封裝為獨立的類別,透過統一介面使用類別,使得變更行為時,不必因行為變化而重新修改類別本身。

以 python 舉個例子,假設我今天有個旅遊類別如下。

class Travel():
    def hotel(self):
        print('Staying at the Taiwan Hotel.')
    def transport(self,distance:int):
        print(f"Walk for {distance / 1} minutes.")

但是我目前有個需求是要新增一個新的交通方式:“開車”,他的時間計算跟原本的走路的計算方式不一樣。 那這時我們可以選擇:

  • 繼承 Travel 類別,並複寫 transport function。
    • 需要為此撰寫一個新的類別,假設 hotel 不一樣也會需要複寫,當有幾種 hotel 跟幾種 transport 的組合,就需要寫多少類別,在維護上會是一大難題。
  • 直接修改 transport
    • 透過參數來選擇使用哪種交通工具,但是會需要確認是否影響了既有功能,當功能是複雜功能時有可能造成無法預期的錯誤。

一開始使用策略模式設計類別就可以避免以上兩者的缺點,我們可以將 transport 會需要作的內容定義為介面。

from abc import ABC,abstractmethod

class TransportStrategy(ABC):
    @abstractmethod
    def transport(self,distance:int):
        pass

定義了每個 transport 都該有的行為後,就可以設計類別會直接執行行為而不用顧慮是哪種 transport。 可以重新定義類別為

class Travel():
    def __init__(self,transport_strategy:TransportStrategy):
        self.transport_handler = transport_strategy()
    def hotel(self):
        print('Staying at the Taiwan Hotel.')
    def transport(self,distance:int):
        self.transport_handler.transport(distance)

然後另外定義各種 TransportStrategy

class WorkTransport(TransportStrategy):
    def transport(self,distance:int):
        print(f"Walk for {distance / 1} minutes.")

class DriveTransport(TransportStrategy):
    def transport(self,distance:int):
        print(f"Walk for {distance / 10} minutes.")

這樣只需要在創建 Travel 類別的物件時,指定 TransportStrategy 就好,更甚至可以另外定義 function 去動態的修改 TransportStrategy。 可以在某些條件下從 work_transport 變為 drive_transport。 這樣子可以解決:

  • 不必為了多種組合而去建立類別。
  • 每個 TransportStrategy 都是獨立的,當我要新增新的 TransportStrategy 並不會影響到原有的 TransportStrategy 的程式碼。
from abc import ABC,abstractmethod

class TransportStrategy(ABC):
    @abstractmethod
    def transport(self,distance:int):
        pass
class WorkTransport(TransportStrategy):
    def transport(self,distance:int):
        print(f"Walk for {distance / 1} minutes.")

class DriveTransport(TransportStrategy):
    def transport(self,distance:int):
        print(f"Walk for {distance / 10} minutes.")

class Travel():
    def __init__(self,transport_strategy:TransportStrategy):
        self.transport_handler = transport_strategy()
    def hotel(self):
        print('Staying at the Taiwan Hotel.')
    def transport(self,distance:int):
        self.transport_handler.transport(distance)

if __name__ == '__main__':
    travel_handler = Travel(WorkTransport)
    travel_handler.transport(10)
    travel_handler = Travel(DriveTransport)
    travel_handler.transport(10)

參考:

使用 Hugo 建立
主題 StackJimmy 設計