---
# System prepended metadata

title: 策略模式 Strategy
tags: [Behavioral Patterns]

---

---
tags: Behavioral Patterns
---

# 策略模式 Strategy

疑問？ Strategy 跟 Context 之間的關係是 aggregation？
> [name=毓昇]






要解決一個class在不同種類或品種時會有不同行為（如：鴨子有些會飛有些不會），最簡單的做法就是把那個行為拉出來用Interface解決，但如果種類越來越多，這可能會造成維護困難。

![](https://i.imgur.com/pKHRiTK.png)
使用Interface的結構圖，每個鴨子都有不同叫法跟會不會飛的行為，每次增加一個鴨子種類的class就要去實作兩個介面。

策略模式設計守則:
1. 把程式中可能變動的部份獨立出來
2. 寫程式是針對介面寫, 不是針對實作方式寫
3. 多用合成, 少用繼承

解法：
當宣告一個鴨子時，我們可以直接**合成**一個鴨子的叫法以及能不能飛(把要使用的介面塞進去class)。

更改過後產生的新圖
![](https://i.imgur.com/traAB0c.png)

總體架構圖
![](https://i.imgur.com/A6JwMI6.png)


**程式說明**
```javascript
public abstract class Duck {
    Flyable flyAble;
    Quackable quackAble;
    public abstract void display();
    public void performFly(){
        if(flyAble != null)
            flyAble.fly();
    }
    public void performQuack() {
        if(quackAble != null)
            quackAble.quack();
    }
    //設定哪種叫法或能不能飛行
    public void setFlyable(Flyable fly){
        flyAble = fly;
    }
    public void setQuackable(Quackable quack){
        quackAble = quack;
    }
}
public class SuperFly implements Flyable {
    public void fly(){
        System.out.println("I'm super flying!!");
    }
}
public class SuperQuack implements Quackable {

    public void quack(){
        System.out.println("I'm super quacking!!");
    }
} 
public class SuperDuck extends Duck {
    public void display(){
        System.out.println("I'm super duck!!");
    }
}
public class DuckTest {
    pubilc static void main(String[] args){
        Duck duck = new SuperDuck();
        // 指定這隻鴨怎麼飛
        duck.setFlyable(new SuperFly());
        // 指定這隻鴨怎麼叫
        duck.setQuackable(new SuperQuack());
        duck.performFly();
        duck.performQuack();
    }
}
```

> [name=閔致]