# Chapter3: 策略模式 (Strategy Pattern)

## This section contain the following items:

1.Strategy Pattern

2.Strategy Pattern Example

## 1.Strategy Pattern

* 策略模式所要解決的問題(痛點)
  * 1.在一個專案中的不同物件, 如果其80%屬性相同, 但在某些方面有差異, 若全部分為不同的類別來寫,勢必會造成**維護不易及程式碼不一致的問題**.
  * 2.在一個專案中的不同物件, 其屬性有互相重複使用的情形.例如有三個動物, A,B的叫聲相同, B,C的飛行方式相同, 如果分別實作三個class, 則會有很多function是重複的. 我們已經知道**code重複的後遺症:維護不易, 無法維持一致性**.

    ![](https://1330730840-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M4M0G8D7wlLIQ3stULq%2F-M4M0IKc4rWLYnAL_jem%2F-M4M0LiRzIU-rS_F9QQT%2FUntitled123.jpg?generation=1586302918284859\&alt=media)
  * 3.如果為了解決2的問題, 使用**繼承**, 考量下面一種情況可能會發生:

    A動物並不會飛, D動物也不會叫, 這麼一來必須在這兩個類別的這些function中取消繼承而來的行為, 一個漏掉就會變成bug; 而且重複的function還是必須得複製貼上,如A,B的叫聲相同, 一樣會有維護不異, 無法維持一致性的問題.

    ![](https://1330730840-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M4M0G8D7wlLIQ3stULq%2F-M4M0IKc4rWLYnAL_jem%2F-M4M0LiTMU0qTcVBiIdW%2FUntitled12.jpg?generation=1586302918321345\&alt=media)
* 策略模式的核心概念
  * 1.找出程式中可能需要變動之處, 把他們獨立出來, 不要與那些不需要更動的程式碼混在一起.
    * 例如:

      ![](https://1330730840-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M4M0G8D7wlLIQ3stULq%2F-M4M0IKc4rWLYnAL_jem%2F-M4M0LiVn2rEl3nVwQrM%2FUntitled22.jpg?generation=1586302918185091\&alt=media)
    * 可以這樣拆分class:

      ![](https://1330730840-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M4M0G8D7wlLIQ3stULq%2F-M4M0IKc4rWLYnAL_jem%2F-M4M0LiX1YUoe7iFS9AO%2FUntitled222.jpg?generation=1586302918859310\&alt=media)
  * 2.寫程式是針對介面(超類別)而寫, 而不是針對實踐方法而寫
    * 介面, 超類別, 多型:
      * 實體化的動作不再需要程式碼中僵化固定成某型態, 而是在runtime時才決定:

        ![](https://1330730840-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M4M0G8D7wlLIQ3stULq%2F-M4M0IKc4rWLYnAL_jem%2F-M4M0LiZVPosBgWCpCd9%2FUntitled2.jpg?generation=1586302918356098\&alt=media)

        ```
          Animal animal = new dog();
          animal.makeSound();
        ```
    * 合成代替繼承
      * 若使用策略模式來套用上述範例, 則可以解決繼承所帶來的問題, 也可以重複使用已經寫好的程式碼:

        ![](https://1330730840-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M4M0G8D7wlLIQ3stULq%2F-M4M0IKc4rWLYnAL_jem%2F-M4M0LiacXKEsVBelJu8%2Fs13.jpg?generation=1586302918288176\&alt=media)

## 2.Strategy Pattern Example:

* 以Javascript為例:

  * [1.以物件導向模式的寫法實作: 架構上可分為策略物件與主體物件](https://codepen.io/JenHsuan/pen/XRjWoN?editors=1011)

    ```
      //策略類別
      var animalA = function(){};
      animalA.prototype.bark = function (){
          return "呱呱"  
      }
      animalA.prototype.fly = function (){
          return "展翅高飛"  
      }

      var animalB = function(){};
      animalB.prototype.bark = function (){
          return "呱呱"  
      }
      animalB.prototype.fly = function (){
          return "滑翔"  
      }

      var animalC = function(){};
      animalC.prototype.bark = function (){
          return "嘰嘰"  
      }
      animalC.prototype.fly = function (){
          return "滑翔"  
      }

      //主體類別
      var animal = function(){
        this.animal = null;
      }
      animal.prototype.setType = function (animal){
          this.animal = animal;
      }
      animal.prototype.bark = function (){
          console.log(this.animal.bark());
      }
      animal.prototype.fly = function (){
          console.log(this.animal.fly());
      }

      //test
      var littleAnimal = new animal();
      littleAnimal.setType(new animalA());
      littleAnimal.bark();
      littleAnimal.fly();
    ```

  ![](https://1330730840-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M4M0G8D7wlLIQ3stULq%2F-M4M0IKc4rWLYnAL_jem%2F-M4M0LickSzpQ4re6aqw%2F%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202017-04-24%20%E4%B8%8A%E5%8D%889.48.45.png?generation=1586302918272145\&alt=media)

  * [2.以Javascript的寫法實作](https://codepen.io/JenHsuan/pen/XRjWoN?editors=1011)

    ```
      //2.以Javascript的寫法實作
      //策略物件
      var barks ={
        "animalA": function (){
          return "呱呱"  
        },
        "animalB": function (){
          return "呱呱"  
        },
        "animalC": function (){
          return "嘰嘰"  
        }
      }

      var flys ={
        "animalA": function (){
          return "展翅高飛"  
        },
        "animalB": function (){
          return "滑翔"  
        },
        "animalC": function (){
          return "滑翔"  
        }
      }

      //主體物件
      var action = function(actions, type){
        console.log(actions[type]());
      }

      action(barks, "animalA")
      action(flys, "animalA")
    ```

  ![](https://1330730840-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M4M0G8D7wlLIQ3stULq%2F-M4M0IKc4rWLYnAL_jem%2F-M4M0LieJSQsOMY3My_s%2F%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7%202017-04-24%20%E4%B8%8A%E5%8D%889.48.45.png?generation=1586302918484977\&alt=media)
