2019年2月17日 星期日

設計模式(1) 策略模式(Strategy Pattern)

此篇介紹GoF設計模式(Design Pattern)的其中一種—策略模式(Strategy Pattern)。



  設計模式的定義是:在物件導向軟體設計過程中針對特定問題的簡潔而優雅的解決方案。

  從這段定義中我們知道,設計模式的使用是要配合問題狀況,並非隨便套用都適合,依照模式設計的優點是簡潔富彈性。

  GoF四人幫整理了23種常見的軟體開發設計模式。在這一系列的文章我應該會一一做筆記(希望能完成> <),首先就從策略模式(Strategy Pattern)開始!


適用問題:

  物件導向設計的繼承有著這樣的缺點:沒辦法處理平行間的關係。例如下圖我們建立了一個鳥類別,另有企鵝、鴕鳥、老鷹、烏鴉四類繼承鳥類別,並承襲fly()這個方法,但實作上企鵝和鴕鳥並不會飛,因此在企鵝和鴕鳥的類別中我們就需要 override (覆寫) fly()使其不飛行,這必須要個別寫,但明明企鵝和鴕鳥在fly()上都是不會飛,有著一樣的設定,實做起來要寫的程式碼其實會是一樣的,如此會造成 duplicate code的狀況,我們並不樂見。
  這時可以使用策略模式的設計來處理,將fly的各種方法獨立寫好,再依需求進行套用。

  另外,在程式設計中,我們也會遇到實作某方案有多種方法可做選擇,例如要到某地我們可以選擇走路也可以坐計程車,使用策略模式來設計方便我們能在run-time時決定要使用何種方法,如此更能靈活運用各種演算法。



  策略模式的定義:
    "Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it." (定義一系列演算法,把他們做封裝,並使他們可以相互替換)

  策略模式原則:
    1. Identify the aspects of your application that vary and separate them from what stays the same. (將變動處從不變動處分開)
    2. Program to an interface, not an implementation. (針對介面設計,而非實作)
    3. Favor composition over inheritance. (包裝優先繼承)


範例:

  各種鴨子,在飛行與叫聲的實作上部分不同,我們增加兩變數 flyBehavior、quackBehavior,如此能在run-time時設定動作採行的演算法。
    建立FlyBehavior interface,底下實作多種飛行的方法。(將所有飛行動作包裝在一起)
    建立QuackBehavior interface,底下實作多種叫聲。(將所有叫聲包裝在一起)

  對於RubberDuck橡膠鴨就會是使用FlyNoWay和Quack類。



  一個基於策略模式的程式至少會有兩部份組成,第一個部份是一組策略類別,策略類別封裝了具體的演算法,並負責具體的計算過程,第二部份是環境類別Context,Context接受客戶端的請求,隨後把請求委託給某一個策略類別,要做到這點Context必須要維持對某個策略物件的引用。

範例:

employee_a = Employee()
employee_a.setSalary(1000)
employee_a.setBonus(AlgorithmA())
employee_a.getBonus()

  Employee類裡的getBonus()方法會拿setBonus()裡設定的算法來計算該員工能拿到多少紅利。
  setBonus()方法就是將請求委託給策略類別,因為Employee類中並沒有計算紅利的方法。




  參考資料:
    1. Head First Design Patterns
    2. JavaScript 設計模式與開發實踐 (博碩出版)






沒有留言:

張貼留言