iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 29
0
Software Development

從生活中認識Design Pattern系列 第 29

[Day29] 策略模式 | Strategy Pattern

文同步分享於個人blog

  • 定義


定義一系列演算法,並將其封裝起來,使他們可以相互替換,演算法的變換不影響使用。

可以把策略想做成多種選項,依照適合的情況選擇適合的項目。比方說連假出遊,可以開車、坐高鐵、坐火車或坐飛機等選項可選。而在程式中也有,如排序法有冒泡排序、插入排序、選擇排序等等選擇。

策略模式通過對演算法的封裝,把使用演算法的責任以及演算法的實作給分開來,並委派不同的物件管理這些演算法。若使用if-else來判斷策略,若策略一多會讓程式變得複雜,在若要對新增刪除或更改演算法,就得異動到原始程式碼,違反了開閉原則。

  • Strategy Pattern 成員


name description
Strategy(抽象策略) 紀錄目前的內部狀態,提供建立備忘錄及回復備忘錄狀態的功能,可以訪問備忘錄內所有訊息。
ConcreteStrategy(實體策略) 保存發起人的內部狀態,在需要的時候提供給發起人。
Context(環境) 管理、保存及讀取備忘錄的功能,但不能對備忘錄的內容進行訪問及修改。

s1

  • Strategy Pattern 實作


一開始有講到連假出遊,可以選擇開車、搭高鐵、坐飛機等不同的方式。而玩剪刀石頭布也是策略的一種,先將抽象策略建立起來,再分別建立剪刀石頭布的類別實作抽象策略。


enum Type { // 建立一個列舉方便等等程式使用
    PAPER, SCISSORS, STONE
}

//抽象策略 
interface Strategy {   
    public void strategyMethod(Type type);    //策略方法
}
//實體策略:布
class Paper implements Strategy {
    public void strategyMethod(Type type) {
        switch(type){
            case PAPER:
                System.out.println("敵人出布,我出布 => 平手");
                break;
            case SCISSORS:
                System.out.println("敵人出剪刀,我出布 => 輸");
                break;
            case STONE:
                System.out.println("敵人出石頭,我出布 => 贏");
                break;
        }
    }
}
//實體策略:剪刀
class Scissors implements Strategy {
    public void strategyMethod(Type type) {
        switch(type){
            case PAPER:
                System.out.println("敵人出布,我出剪刀 => 贏");
                break;
            case SCISSORS:
                System.out.println("敵人出剪刀,我出剪刀 => 平手");
                break;
            case STONE:
                System.out.println("敵人出石頭,我出剪刀 => 輸");
                break;
        }
    }
}
//實體策略:石頭
class Stone implements Strategy {
    public void strategyMethod(Type type) {
        switch(type){
            case PAPER:
                System.out.println("敵人出布,我出石頭 => 輸");
                break;
            case SCISSORS:
                System.out.println("敵人出剪刀,我出石頭 => 贏");
                break;
            case STONE:
                System.out.println("敵人出石頭,我出石頭 => 平手");
                break;
        }
    }
}

接著將環境建立起來,並在內部實作設定策略及執行策略的方法。

//環境
class Context {
    private Strategy strategy;
    public Strategy getStrategy() {
        return strategy;
    }
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    public void strategyMethod(Type type) {
        strategy.strategyMethod(type);
    }
}

最後我們用Scanner選擇猜拳要出什麼。


import java.util.*;

public class StrategyPattern {
    public static void main(String[] args) {
        Context c = new Context(); // 建立環境
        Strategy paper = new Paper(); // 建立剪刀石頭布
        Strategy scissors = new Scissors();
        Strategy stone = new Stone();
        Type[] arr = {Type.PAPER, Type.SCISSORS, Type.STONE};  
        Scanner scanner = new Scanner(System.in);
        System.out.println("剪刀石頭布!!!");
        Random ran = new Random();
        while(true){
            int num = ran.nextInt(3)+1;
            System.out.println("請出拳(1:剪刀;2:石頭;3:布):");
            int input = scanner.nextInt();
            switch(input){  // 根據輸入不同的數字選擇不同策略
                case 1:
                    c.setStrategy(scissors);
                    break;
                case 2:
                    c.setStrategy(stone);
                    break;
                case 3:
                    c.setStrategy(paper);
                    break;
            }
            c.strategyMethod(arr[num - 1]);
            
            System.out.println("-----------------");
        }
    }
}

output

  • 小結


Strategy Pattern的目標

定義一系列演算法,並將其封裝起來,使他們可以相互替換,演算法的變換不影響使用。

Strategy Pattern的成員
Strategy(抽象策略):紀錄目前的內部狀態,提供建立備忘錄及回復備忘錄狀態的功能,可以訪問備忘錄內所有訊息。
ConcreteStrategy(實體策略):保存發起人的內部狀態,在需要的時候提供給發起人。
Context(環境):管理、保存及讀取備忘錄的功能,但不能對備忘錄的內容進行訪問及修改。
Strategy Pattern的優缺點
優點
1. 提供一系列可重複使用的演算法,適當的使用繼承可把共用程式碼轉移到父類別內,避免重複。
2. 提供相同行為不同實作方式,可以根據不同時間空間選擇適當的策略。
3. 在不修改原始程式碼的情況下,增加新的演算法,符合開閉原則。
4. 演算法的使用放到環境類別,演算法的實作放到具體類別,讓兩者分離。
缺點
1. Client必須了解所有演算法區別,才能適當使用。
2. 產生很多的策略類別。
Strategy Pattern的使用時機
1. 當系統需要動態的選擇策略時。
2. 一個類別定義多種行為,且這些行為在這個類別中有多個條件(if-else)語法形式出現時。
3. 系統演算法獨立,且要求對client隱藏實作細節時。
  • 範例程式碼


Strategy Pattern 實作

  • References


策略模式(策略设计模式)


上一篇
[Day28] 觀察者模式 | Observer Pattern
下一篇
[Day30] 總結
系列文
從生活中認識Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言