意圖
定義了算法簇,分別封裝起來,讓他們之間可以互相替換。策略模式讓算法得變化獨立於使用算法得客戶。
動機
生活中,我們常常遇到實現某種目標存在多種方式可供選擇的情況,例如:我們可以選擇自駕、搭地鐵、搭公交或者騎自行車等方式上下班。
類似的,在開發某一個功能時也可能存在多種算法或者策略,可以根據環境或者條件的不同選擇不同的算法或者策略來實現該功能,如數據排序策略有冒泡排序、選擇排序、插入排序、二叉樹排序等。
適用性
策略模式常見的使用場景如:
- 一個系統需要動態地在幾種算法中選擇一種時,可將每個算法封裝到策略類中。
- 一個類定義了多種行爲,並且這些行爲在這個類的操作中以多個條件語句的形式出現,可將每個條件分支移入它們各自的策略類中以代替這些條件語句。
- 系統中各算法彼此完全獨立,且要求對客戶隱藏具體算法的實現細節時。
- 系統要求使用算法的客戶不應該知道其操作的數據時,可使用策略模式來隱藏與算法相關的數據結構。
- 多個類只區別在表現行爲不同,可以使用策略模式,在運行時動態選擇具體要執行的行爲。
結構
策略模式模式的主要角色有:
- 抽象策略類(
Strategy
):定義了一個算法族; - 具體策略類(
ConcreteStrategy
):提供具體的算法實現; - 環境類(
Context
):持有一個策略類的引用,最終給客戶端調用。
實現
// 抽象策略接口
public interface Strategy {
// 策略方法
void strategyMethod();
}
//具體策略類A
public class ConcreteStrategyA implements Strategy {
@Override
public void strategyMethod() {
System.out.println("執行 ConcreteStrategyA 的策略方法。。。");
}
}
//具體策略類B
public class ConcreteStrategyB implements Strategy {
@Override
public void strategyMethod() {
System.out.println("執行 ConcreteStrategyB 的策略方法。。。");
}
}
// 環境類
public class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
// 通過 set 不同的 strategy 對象,而動態地改變調用的策略方法
public void operation() {
strategy.strategyMethod();
}
}
// 測試客戶端
public class TestClient {
public static void main(String[] args) {
Context context = new Context();
Strategy concreteA = new ConcreteStrategyA();
Strategy concreteB = new ConcreteStrategyB();
context.setStrategy(concreteA);
context.operation();
context.setStrategy(concreteB);
context.operation();
}
}
已知應用
- javax.servlet.http.HttpServlet
- javax.servlet.Filter#doFilter()
相關模式
策略模式與模板方法模式區別:
1、類之間的關係不同:策略模式使用對象組合的方式,客戶可以在運行時改變他們的算法,設計更有彈性;而模板方法模式區使用的繼承的方式,可以把重複用到的代碼都封裝到基類中,讓所有子類共享,代碼更緊湊,效率更高。
2、執行流程:模板模式是按照一定步驟執行程序的,任何一個節點的重載不會影響到這個次序;而策略模式各各算法彼此完全獨立,沒有次序要求。
參考資料
- 《
Head First
設計模式》 - 圖說設計模式
- Java設計模式:23種設計模式全面解析(超級詳細)