# 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重複的後遺症:維護不易, 無法維持一致性**.

    ![](/files/-M4M0LiRzIU-rS_F9QQT)
  * 3.如果為了解決2的問題, 使用**繼承**, 考量下面一種情況可能會發生:

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

    ![](/files/-M4M0LiTMU0qTcVBiIdW)
* 策略模式的核心概念
  * 1.找出程式中可能需要變動之處, 把他們獨立出來, 不要與那些不需要更動的程式碼混在一起.
    * 例如:

      ![](/files/-M4M0LiVn2rEl3nVwQrM)
    * 可以這樣拆分class:

      ![](/files/-M4M0LiX1YUoe7iFS9AO)
  * 2.寫程式是針對介面(超類別)而寫, 而不是針對實踐方法而寫
    * 介面, 超類別, 多型:
      * 實體化的動作不再需要程式碼中僵化固定成某型態, 而是在runtime時才決定:

        ![](/files/-M4M0LiZVPosBgWCpCd9)

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

        ![](/files/-M4M0LiacXKEsVBelJu8)

## 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();
    ```

  ![](/files/-M4M0LickSzpQ4re6aqw)

  * [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")
    ```

  ![](/files/-M4M0LieJSQsOMY3My_s)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jen-hsuan-hsieh.gitbook.io/design-pattern/chapter3_ce_lve_mo_shi__strategy_pattern.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
