策略模式定義
實現某一個功能有多條途徑,每一條途徑對應一種算法,此時我們可以使用一種設計模式來實現靈活地選擇解決途徑,也能夠方便地增加新的解決途徑
策略模式的主要目的是將算法的定義與使用分開,也就是將算法的行爲和環境分開
策略模式優點
- 策略模式提供了對“開閉原則”的完美支持,用戶可以在不修改原有系統的基礎上選擇算法或行爲,也可以靈活地增加新的算法或行爲。
- 策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行爲族,恰當使用繼承可以把公共的代碼移到抽象策略類中,從而避免重複的代碼。
- 策略模式提供了一種可以替換繼承關係的辦法。如果不使用策略模式,那麼使用算法的環境類就可能會有一些子類,每一個子類提供一種不同的算法。但是,這樣一來算法的使用就和算法本身混在一起,不符合“單一職責原則”,決定使用哪一種算法的邏輯和該算法本身混合在一起,從而不可能再獨立演化;而且使用繼承無法實現算法或行爲在程序運行時的動態切換。
- 使用策略模式可以避免多重條件選擇語句。多重條件選擇語句不易維護,它把採取哪一種算法或行爲的邏輯與算法或行爲本身的實現邏輯混合在一起,將它們全部硬編碼(Hard Coding)在一個龐大的多重條件選擇語句中,比直接繼承環境類的辦法還要原始和落後。
- 策略模式提供了一種算法的複用機制,由於將算法單獨提取出來封裝在策略類中,因此不同的環境類可以方便地複用這些策略類。
策略模式缺點
- 客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法。換言之,策略模式只適用於客戶端知道所有的算法或行爲的情況。
- 策略模式將造成系統產生很多具體策略類,任何細小的變化都將導致系統要增加一個新的具體策略類。
- 無法同時在客戶端使用多個策略類,也就是說,在使用策略模式時,客戶端每次只能使用一個策略類,不支持使用一個策略類完成部分功能後再使用另一個策略類來完成剩餘功能的情況。
應用場景
- 一個系統需要動態地在幾種算法中選擇一種,那麼可以將這些算法封裝到一個個的具體算法類中,而這些具體算法類都是一個抽象算法類的子類。換言之,這些具體算法類均有統一的接口,根據“里氏代換原則”和麪向對象的多態性,客戶端可以選擇使用任何一個具體算法類,並只需要維持一個數據類型是抽象算法類的對象。
- 一個對象有很多的行爲,如果不用恰當的模式,這些行爲就只好使用多重條件選擇語句來實現。此時,使用策略模式,把這些行爲轉移到相應的具體策略類裏面,就可以避免使用難以維護的多重條件選擇語句。
- 不希望客戶端知道複雜的、與算法相關的數據結構,在具體策略類中封裝算法與相關的數據結構,可以提高算法的保密性與安全性。
模式結構
- 策略模式是對算法的封裝,它把算法的責任和算法本身分割開,委派給不同的對象管理
- 環境類是需要使用算法的類。在一個系統中可以存在多個環境類,它們可能需要重用一些相同的算法
代碼實例
abstract class AbstractStrategy {
public abstract void algorithm(); //聲明抽象算法
}
class ConcreteStrategyA extends AbstractStrategy {
//算法的具體實現
public void algorithm() {
//算法A
}
}
class Context {
private AbstractStrategy strategy; //維持一個對抽象策略類的引用
public void setStrategy(AbstractStrategy strategy) {
this.strategy= strategy;
}
//調用策略類中的算法
public void algorithm() {
strategy.algorithm();
}
}
Context context = new Context();
AbstractStrategy strategy;
strategy = new ConcreteStrategyA(); //可在運行時指定類型
context.setStrategy(strategy);
context.algorithm();
擴展
策略模式的兩個典型應用
- Java SE的容器佈局管理
策略模式用於算法的自由切換和擴展,它是應用較爲廣泛的設計模式之一。策略模式對應於解決某一問題的一個算法族,允許用戶從該算法族中任選一個算法來解決某一問題,同時可以方便地更換算法或者增加新的算法。只要涉及到算法的封裝、複用和切換都可以考慮使用策略模式