前言
在策略模式(Strategy Pattern)中,一個類的行爲或其算法可以在運行時更改。這種類型的設計模式屬於行爲型模式。在策略模式中,我們創建表示各種策略的對象和一個行爲隨着策略對象改變而改變的 context 對象。策略對象改變 context 對象的執行算法。
定義一系列算法,將每個算法封裝到具有公共接口的一系列策略類中,從而使它們可以相互替換 & 讓算法可在不影響客戶端的情況下發生變化。
解決的問題
將算法的責任和本身進行解耦,使得:
1、算法可獨立於使用外部而變化;
2、客戶端方便根據外部條件選擇不同策略來解決不同問題;
策略模式僅僅封裝算法(包括添加 & 刪除),但策略模式並不決定在何時使用何種算法,算法的選擇由客戶端來決定。
原理
UML類圖
實例講解
背景:小成有一家百貨公司,最近在定年度的促銷活動。
衝突:每個節日用同一個促銷活動太枯燥,沒吸引力。
解決方案:針對不同節目使用不同促銷活動進行促銷。
步驟1:定義抽象策略角色(Strategy),百貨公司所有促銷活動的共同接口。
public abstract class Strategy {
public abstract void Show();
}
步驟2:定義具體策略角色(Concrete Strategy),每個節日具體的促銷活動。
//爲春節準備的促銷活動A
class StrategyA extends Strategy{
@Override
public void show() {
System.out.println("爲春節準備的促銷活動A");
}
}
//爲中秋節準備的促銷活動B
class StrategyB extends Strategy{
@Override
public void show() {
System.out.println("爲中秋節準備的促銷活動B");
}
}
//爲聖誕節準備的促銷活動C
class StrategyC extends Strategy{
@Override
public void show() {
System.out.println("爲聖誕節準備的促銷活動C");
}
}
步驟3:定義環境角色(Context),用於連接上下文,即把促銷活動推銷給客戶,這裏可以理解爲銷售員。
class SalesMan{
//持有抽象策略角色的引用
private Strategy strategy;
//生成銷售員實例時告訴銷售員什麼節日(構造方法)
//使得讓銷售員根據傳入的參數(節日)選擇促銷活動(這裏使用一個簡單的工廠模式)
public SalesMan(String festival) {
switch ( festival) {
//春節就使用春節促銷活動
case "A":
strategy = new StrategyA();
break;
//中秋節就使用中秋節促銷活動
case "B":
strategy = new StrategyB();
break;
//聖誕節就使用聖誕節促銷活動
case "C":
strategy = new StrategyC();
break;
}
}
//向客戶展示促銷活動
public void salesManShow(){
strategy.show();
}
}
步驟4:客戶端調用-讓銷售員進行促銷活動的落地。
public class StrategyPattern{
public static void main(String[] args){
SalesMan mSalesMan ;
//春節來了,使用春節促銷活動
System.out.println("對於春節:");
mSalesMan = new SalesMan("A");
mSalesMan.salesManShow();
//中秋節來了,使用中秋節促銷活動
System.out.println("對於中秋節:");
mSalesMan = new SalesMan("B");
mSalesMan.salesManShow();
//聖誕節來了,使用聖誕節促銷活動
System.out.println("對於聖誕節:");
mSalesMan = new SalesMan("C");
mSalesMan.salesManShow();
}
}
結果輸出
對於春節:
爲春節準備的促銷活動A
對於中秋節:
爲中秋節準備的促銷活動B
對於聖誕節:
爲聖誕節準備的促銷活動B
優缺點
優點
1、策略類之間可以自由切換,由於策略類都實現同一個接口,所以使它們之間可以自由切換。
2、易於擴展,增加一個新的策略只需要添加一個具體的策略類即可,基本不需要改變原有的代碼,符合“開閉原則“。
3、避免使用多重條件選擇語句(if else),充分體現面向對象設計思想。
缺點
1、客戶端必須知道所有的策略類,並自行決定使用哪一個策略類,不符合迪米特法則(Law of Demeter)或者叫最少知識原則(Least Knowledge Principle 簡寫LKP)。要解決這個問題可以結合工廠模式一起使用。
關於策略模式與工廠模式一起結合使用的例子可以參考這篇博文:https://www.jianshu.com/p/0280f5f59c6e
2、策略模式將造成產生很多策略類,可以通過使用享元模式在一定程度上減少對象的數量。
應用場景
動態選擇多種複雜行爲。
1、如果在一個系統裏面有許多類,它們之間的區別僅在於它們的行爲,那麼使用策略模式可以動態地讓一個對象在許多行爲中選擇一種行爲。
2、一個系統需要動態地在幾種算法中選擇一種。
3、如果一個對象有很多的行爲,如果不用恰當的模式,這些行爲就只好使用多重的條件選擇語句來實現。
注意事項:如果一個系統的策略多於四個,就需要考慮使用混合模式,解決策略類膨脹的問題。