1 什么是策略模式
在策略模式中,定義了一些獨立的類來封裝不同的算法,每一個類封裝一種具體的算法,在這里,每一個封裝算法的類都可以稱之為一種策略(Strategy),為了保證這些策略在使用時具有一致性,一般會提供一個抽象的策略類來做規(guī)則的定義,而每種算法則對應(yīng)于一個具體策略類。
策略模式的主要目的是將算法的定義與使用分開,也就是將算法的行為和環(huán)境分開,將算法的定義放在專門的策略類中,每一個策略類封裝了一種實現(xiàn)算法,使用算法的環(huán)境類針對抽象策略類進(jìn)行編程,符合“依賴倒轉(zhuǎn)原則”。在出現(xiàn)新的算法時,只需要增加一個新的實現(xiàn)了抽象策略類的具體策略類即可。
策略模式(Strategy Pattern):定義一系列算法類,將每一個算法封裝起來,并讓它們可以相互替換,策略模式讓算法獨立于使用它的客戶而變化,也稱為政策模式(Policy)。策略模式是一種對象行為型模式。
2 模式的結(jié)構(gòu)
策略模式的UML類圖如下:

在策略模式結(jié)構(gòu)圖中包含如下幾個角色:
Context(環(huán)境類):環(huán)境類是使用算法的角色,它在解決某個問題(即實現(xiàn)某個方法)時可以采用多種策略。在環(huán)境類中維持一個對抽象策略類的引用實例,用于定義所采用的策略。
Strategy(抽象策略類):它為所支持的算法聲明了抽象方法,是所有策略類的父類,它可以是抽象類或具體類,也可以是接口。環(huán)境類通過抽象策略類中聲明的方法在運行時調(diào)用具體策略類中實現(xiàn)的算法。
ConcreteStrategy(具體策略類):它實現(xiàn)了在抽象策略類中聲明的算法,在運行時,具體策略類將覆蓋在環(huán)境類中定義的抽象策略類對象,使用一種具體的算法實現(xiàn)某個業(yè)務(wù)處理。
3 典型代碼
策略模式是一個比較容易理解和使用的設(shè)計模式,策略模式是對算法的封裝,它把算法的責(zé)任和算法本身分割開,委派給不同的對象管理。策略模式通常把一個系列的算法封裝到一系列具體策略類里面,作為抽象策略類的子類。環(huán)境類是需要使用算法的類。在一個系統(tǒng)中可以存在多個環(huán)境類,它們可能需要重用一些相同的算法。
在使用策略模式時,首先應(yīng)該創(chuàng)建一個抽象策略類,其典型代碼如下所示:
public abstract class AbstractStrategy {
public abstract void algorithm();
}
封裝每一種具體算法的類作為該抽象策略類的子類,期典型代碼如下:
public class ConcreteStrategyA extends AbstractStrategy {
public void algorithm() {
//todo
}
}
public class ConcreteStrategyB extends AbstractStrategy {
public void algorithm() {
//todo
}
}
在Context類與抽象策略類之間建立一個關(guān)聯(lián)關(guān)系,其典型代碼如下:
public class Context {
private AbstractStrategy strategy;
public Context(AbstractStrategy strategy){
this.strategy = strategy;
}
public void algorithm(){
strategy.algorithm();
}
}
客戶端代碼如下:
public class Client {
public static void main(String[] args) {
AbstractStrategy strategy = new ConcreteStrategyA();
Context context = new Context(strategy);
context.algorithm();
}
}
也可以將具體策略類類名存儲在配置文件中,通過反射來動態(tài)創(chuàng)建具體策略對象,從而使得用戶可以靈活地更換具體策略類,增加新的具體策略類也很方便。策略模式提供了一種可插入式(Pluggable)算法的實現(xiàn)方案。
4策略模式和模板方法模式的區(qū)別
Template Method模式是將相同的算法放在一個類中,將算法變化的部分放在子類中實現(xiàn),策略模式是將不同的算法用不同的策略類表示,似乎沒有太大的區(qū)別。
認(rèn)真想想還是有區(qū)別的。
策略模式的策略類中的方法一般是public的,封裝的算法是任意給用戶使用,而模板方法模式中的虛方法更多的是有限制的,一般不希望被外部調(diào)用,而是在模板方法中在固定的順序位置被調(diào)用。
5 優(yōu)點和缺點
5.1 優(yōu)點
策略模式的主要優(yōu)點如下:
策略模式提供了對“開閉原則”的完美支持,用戶可以在不修改原有系統(tǒng)的基礎(chǔ)上選擇算法或行為,也可以靈活地增加新的算法或行為。
策略模式提供了管理相關(guān)的算法族的辦法。策略類的等級結(jié)構(gòu)定義了一個算法或行為族,恰當(dāng)使用繼承可以把公共的代碼移到抽象策略類中,從而避免重復(fù)的代碼。
策略模式提供了一種可以替換繼承關(guān)系的辦法。如果不使用策略模式,那么使用算法的環(huán)境類就可能會有一些子類,每一個子類提供一種不同的算法。但是,這樣一來算法的使用就和算法本身混在一起,不符合“單一職責(zé)原則”,決定使用哪一種算法的邏輯和該算法本身混合在一起,從而不可能再獨立演化;而且使用繼承無法實現(xiàn)算法或行為在程序運行時的動態(tài)切換。
使用策略模式可以避免多重條件選擇語句。多重條件選擇語句不易維護(hù),它把采取哪一種算法或行為的邏輯與算法或行為本身的實現(xiàn)邏輯混合在一起,將它們?nèi)坑簿幋a(Hard Coding)在一個龐大的多重條件選擇語句中,比直接繼承環(huán)境類的辦法還要原始和落后。
策略模式提供了一種算法的復(fù)用機制,由于將算法單獨提取出來封裝在策略類中,因此不同的環(huán)境類可以方便地復(fù)用這些策略類。
5.2 缺點
策略模式的主要缺點如下:
- 客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。這就意味著客戶端必須理解這些算法的區(qū)別,以便適時選擇恰當(dāng)?shù)乃惴?。換言之,策略模式只適用于客戶端知道所有的算法或行為的情況。
- 策略模式將造成系統(tǒng)產(chǎn)生很多具體策略類,任何細(xì)小的變化都將導(dǎo)致系統(tǒng)要增加一個新的具體策略類。
- 無法同時在客戶端使用多個策略類,也就是說,在使用策略模式時,客戶端每次只能使用一個策略類,不支持使用一個策略類完成部分功能后再使用另一個策略類來完成剩余功能的情況。
6 適用環(huán)境
在以下情況下可以考慮使用策略模式:
如果在一個系統(tǒng)里面有許多類,它們之間的區(qū)別僅在于它們的行為,那么使用策略模式可以動態(tài)地讓一個對象在許多行為中選擇一種行為。
一個系統(tǒng)需要動態(tài)地在幾種算法中選擇一種,那么可以將這些算法封裝到一個個的具體算法類中,而這些具體算法類都是一個抽象算法類的子類。
一個對象有很多的行為,如果不用恰當(dāng)?shù)哪J剑@些行為就只好使用多重條件選擇語句來實現(xiàn)。此時,使用策略模式,把這些行為轉(zhuǎn)移到相應(yīng)的具體策略類里面,就可以避免使用難以維護(hù)的多重條件選擇語句。
不希望客戶端知道復(fù)雜的、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu),在具體策略類中封裝算法與相關(guān)的數(shù)據(jù)結(jié)構(gòu),可以提高算法的保密性與安全性。