策略模式

📢 本文由 gemini-2.5-flash 翻譯

策略模式 物件行為模式

目的

定義一系列演算法,將它們個別封裝起來,並使其可以互相替換。此模式讓演算法能夠獨立於使用它們的客戶而變化。

結構

策略模式

其中:

  • Strategy (策略) 定義所有支援演算法的通用介面。Context 使用這個介面來呼叫某個 ConcreteStrategy 所定義的演算法。

  • ConcreteStrategy (具體策略) 以 Strategy 介面實作某個具體演算法。

  • Context (上下文) 用一個 ConcreteStrategy 物件來配置;維護一個對 Strategy 物件的參照;可定義一個介面來讓 Strategy 存取它的資料。

適用性

策略模式適用於:

  • 許多相關的類別僅僅是行為有所不同。「策略」提供了一種方法,用多個行為中的其中一個行為來配置一個類別。

  • 需要使用一個演算法的不同變體。例如,定義一些反映不同空間的空間/時間權衡演算法。當這些變體實作為一個演算法的類別層次時,可以使用策略模式。

  • 演算法使用客戶不應知道的資料。可使用策略模式,以避免揭露複雜且與演算法相關的資料結構。

  • 一個類別定義了多種行為,並且這些行為在這個類別的操作中以多個條件陳述式的形式出現,可將相關的條件分支移入它們各自的 Strategy 類別中,以代替這些條件陳述式。

範例 1

某間大型購物中心欲開發一套收銀軟體,要求其能夠支援購物中心在不同時期推出的各種促銷活動,例如打折、回饋(例如,滿 300 回饋 100)等等。現採用策略模式實作該要求,所設計的類別圖如下所示:

策略模式-例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import java.util.*;

enum TYPE { NORMAL, CASH_DISCOUNT, CASH_RETURN};

interface CashSuper {
    public double acceptCash(double money);
}

class CashNormal implements CashSuper { // 正常收費子類別
    public double acceptCash(double money) {
        return money;
    }
}
class CashDiscount implements CashSuper {
    private double moneyDiscount; // 折扣率
    public CashDiscount(double moneyDiscount) {
        this moneyDiscount = moneyDiscount;
    }
    public double acceptCash(double money) {
        return money* moneyDiscount;
    }
}

class CashReturn implements CashSuper { // 滿額回饋
    private double moneyCondition;
    private double moneyReturn;
    public CashReturn(double moneyCondition, double moneyReturn) {
        this.moneyCondition = moneyCondition; // 滿額金額
        this.moneyReturn = moneyReturn; // 回饋金額
    }
    public double acceptCash(double money) {
        double result = money;
        if(money >= moneyCondition )
            result = money - Math.floor(money / moneyCondition) * moneyReturn;
        return result;
    }
}

class CashContext {
    private CashSuper cs;
    private TYPE t;
    public CashContext(TYPE t) {
        switch(t) {
            case NORMAL: // 正常收費
                cs = new CashNormal();
                break;
            case CASH_DISCOUNT: // 打 8 折
                cs = new CashDiscount(0.8);
                break;
            case CASH_RETURN: // 滿 300 回饋 100
                cs = new CashReturn(300, 100);
                break;
        }
    }
    public double GetResult(double money) {
        return cs.acceptCash(money);
    }
// 此處省略 main() 函式
}

範例 2

加減乘

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class StrategyPattern {
    public static void main(String[] args) {
        Strategy add = new AddStrategy();
        Strategy subtraction = new SubtractionStrategy();
        Strategy multiply = new MultiplyStrategy();

        OperationContext context = new OperationContext(add);
        context.Operation(1, 2);

        context = new OperationContext(subtraction);
        context.Operation(1, 2);

        context = new OperationContext(multiply);
        context.Operation(1, 2);
    }
}

class OperationContext{
    private Strategy strategy;

    public OperationContext(Strategy strategy){
        this.strategy = strategy;
    }

    public void Operation(int a, int b){
        strategy.operation(a, b);
    }

}

interface Strategy{
    public void operation(int a, int b);
}

class AddStrategy implements Strategy{
    @Override
    public void operation(int a, int b){
        System.out.println(a + b);
    }
}

class SubtractionStrategy implements Strategy{
    @Override
    public void operation(int a, int b){
        System.out.println(a - b);
    }
}

class MultiplyStrategy implements Strategy{
    @Override
    public void operation(int a, int b){
        System.out.println(a * b);
    }
}