策略模式是一種行為設(shè)計模式,?它能讓你定義一系列算法,?并將每種算法分別放入獨立的類中,?以使算法的對象能夠相互替換。
策略模式建議找出負(fù)責(zé)用許多不同方式完成特定任務(wù)的類,?然后將其中的算法抽取到一組被稱為策略的獨立類中。
名為上下文的原始類必須包含一個成員變量來存儲對于每種策略的引用。?上下文并不執(zhí)行任務(wù),?而是將工作委派給已連接的策略對象。
上下文不負(fù)責(zé)選擇符合任務(wù)需要的算法——客戶端會將所需策略傳遞給上下文。?實際上,?上下文并不十分了解策略,?它會通過同樣的通用接口與所有策略進(jìn)行交互,?而該接口只需暴露一個方法來觸發(fā)所選策略中封裝的算法即可。
因此,?上下文可獨立于具體策略。?這樣你就可在不修改上下文代碼或其他策略的情況下添加新算法或修改已有算法了。
策略模式結(jié)構(gòu)
上下文?(Context)?維護(hù)指向具體策略的引用,?且僅通過策略接口與該對象進(jìn)行交流。
策略?(Strategy)?接口是所有具體策略的通用接口,?它聲明了一個上下文用于執(zhí)行策略的方法。
具體策略?(Concrete Strategies)?實現(xiàn)了上下文所用算法的各種不同變體。
當(dāng)上下文需要運行算法時,?它會在其已連接的策略對象上調(diào)用執(zhí)行方法。?上下文不清楚其所涉及的策略類型與算法的執(zhí)行方式。
客戶端?(Client)?會創(chuàng)建一個特定策略對象并將其傳遞給上下文。?上下文則會提供一個設(shè)置器以便客戶端在運行時替換相關(guān)聯(lián)的策略。
實現(xiàn)方式
從上下文類中找出修改頻率較高的算法?(也可能是用于在運行時選擇某個算法變體的復(fù)雜條件運算符)。
聲明該算法所有變體的通用策略接口。
將算法逐一抽取到各自的類中,?它們都必須實現(xiàn)策略接口。
在上下文類中添加一個成員變量用于保存對于策略對象的引用。?然后提供設(shè)置器以修改該成員變量。?上下文僅可通過策略接口同策略對象進(jìn)行交互,?如有需要還可定義一個接口來讓策略訪問其數(shù)據(jù)。
客戶端必須將上下文類與相應(yīng)策略進(jìn)行關(guān)聯(lián),?使上下文可以預(yù)期的方式完成其主要工作。
策略模式優(yōu)缺點
優(yōu)點:
你可以在運行時切換對象內(nèi)的算法。
?你可以將算法的實現(xiàn)和使用算法的代碼隔離開來。
?你可以使用組合來代替繼承。
?開閉原則。?你無需對上下文進(jìn)行修改就能夠引入新的策略。
缺點:
?如果你的算法極少發(fā)生改變,?那么沒有任何理由引入新的類和接口。?使用該模式只會讓程序過于復(fù)雜。
?客戶端必須知曉策略間的不同——它需要選擇合適的策略。
?許多現(xiàn)代編程語言支持函數(shù)類型功能,?允許你在一組匿名函數(shù)中實現(xiàn)不同版本的算法。?這樣,?你使用這些函數(shù)的方式就和使用策略對象時完全相同,?無需借助額外的類和接口來保持代碼簡潔。
Java示例代碼:
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(2022, 528);
? ? ? ? context = new OperationContext(subtraction);
? ? ? ? context.Operation(2022, 528);
? ? ? ? context = new OperationContext(multiply);
? ? ? ? context.Operation(2022, 528);
? ? }
}
class OperationContext {
? ? private Strategy strategy;
? ? public OperationContext(Strategy strategy) {
? ? ? ? this.strategy = strategy;
? ? }
? ? public void Operation(int a, int b) {
? ? ? ? strategy.TwoNumberOperation(a, b);
? ? }
}
interface Strategy {
? ? public void TwoNumberOperation(int a, int b);
}
class AddStrategy implements Strategy {
? ? @Override
? ? public void TwoNumberOperation(int a, int b) {
? ? ? ? System.out.println(a + b);
? ? }
}
class SubtractionStrategy implements Strategy {
? ? @Override
? ? public void TwoNumberOperation(int a, int b) {
? ? ? ? System.out.println(a - b);
? ? }
}
class MultiplyStrategy implements Strategy {
? ? @Override
? ? public void TwoNumberOperation(int a, int b) {
? ? ? ? System.out.println(a * b);
? ? }
}