定義
策略(Strategy)模式定義了一系列算法,並將每個算法封裝起來,使它們可以相互替換,且算法的變化不會影響使用算法的客戶,通過對算法進行封裝,把使用算法的責任和算法的實現分割開來,並委派給不同的對象對這些算法進行實現和管理。
策略模式屬於對象行爲型模式。
要點
優點:
- 多重條件語句不易維護,而使用策略模式可以避免使用多重條件語句。
- 提供了一系列的可供重用的算法族,恰當使用繼承可以把算法族的公共代碼轉移到父類裏面,從而避免重複的代碼。
- 可以提供相同行爲的不同實現,客戶可以根據不同時間或空間要求選擇不同的。
- 提供了對開閉原則的完美支持,可以在不修改原代碼的情況下,靈活增加新算法。
- 把算法的使用放到環境類中,而算法的實現移到具體策略類中,實現了二者的分離。
缺點:
- 客戶端必須理解所有策略算法的區別,以便適時選擇恰當的算法類。
- 策略模式造成很多的策略類。
主要角色:
抽象策略(Strategy):定義了一個公共接口,各種不同的算法以不同的方式實現這個接口,環境角色使用這個接口調用不同的算法,一般使用接口或抽象類實現。
具體策略(Concrete Strategy):實現了抽象策略定義的接口,提供具體的算法實現。
環境(Context):持有一個策略類的引用,最終給客戶端調用。
場景
某商場舉辦回饋會員活動,促銷購物優惠規則如下:
- 對初級會員提供10%的促銷折扣。
- 對中級會員提供20%的促銷折扣。
- 對高級會員提供30%的促銷折扣。
實現
MemberStrategy
/**
* 會員優惠策略
*/
public interface MemberStrategy {
/**
* 根據會員等級計算最終價格
*/
double discountPrice(double originalPrice);
}
PrimaryMemberStrategy
/**
* 初級會員策略
*/
public class PrimaryMemberStrategy implements MemberStrategy{
@Override
public double discountPrice(double originalPrice) {
System.out.println("您是初級會員,享受10%的購物折扣");
return originalPrice * 0.9;
}
}
IntermediateMemberStrategy
/**
* 中級會員策略
*/
public class IntermediateMemberStrategy implements MemberStrategy {
@Override
public double discountPrice(double originalPrice) {
System.out.println("您是中級會員,享受20%的購物折扣");
return originalPrice * 0.8;
}
}
AdvancedMemberStrategy
/**
* 高級會員策略
*/
public class AdvancedMemberStrategy implements MemberStrategy {
@Override
public double discountPrice(double originalPrice) {
System.out.println("您是高級會員,享受30%的購物折扣");
return originalPrice * 0.7;
}
}
ShoppingContext
/**
* 購物環境類
*/
public class ShoppingContext {
/**
* 持有一個具體的策略對象
*/
private MemberStrategy strategy;
public ShoppingContext(MemberStrategy strategy){
this.strategy = strategy;
}
/**
* 計算商品的價格
*/
public void handle(double originalPrice){
double discountPrice = this.strategy.discountPrice(originalPrice);
System.out.println(String.format("您的購物商品原價爲:%s元,優惠後您需要支付%s元", originalPrice, discountPrice));
}
public void setStrategy(MemberStrategy strategy) {
this.strategy = strategy;
}
}
Client
public class Client {
public static void main(String[] args) {
ShoppingContext shoppingContext = new ShoppingContext(new PrimaryMemberStrategy());
shoppingContext.handle(1000.0);
shoppingContext.setStrategy(new AdvancedMemberStrategy());
shoppingContext.handle(1000.0);
}
}
-------------------輸出--------------------
您是初級會員,享受10%的購物折扣
您的購物商品原價爲:1000.0元,優惠後您需要支付900.0元
您是高級會員,享受30%的購物折扣
您的購物商品原價爲:1000.0元,優惠後您需要支付700.0元
源碼
總結
策略模式的重心不是如何實現算法,而是如何組織、調用這些算法,從而讓程序結構更靈活,具有更好的維護性和擴展性。
適用場景:
- 一個系統需要動態地在幾種算法中選擇一種時,可將每個算法封裝到策略類中。
- 一個類定義了多種行爲,並且這些行爲在這個類的操作中以多個條件語句的形式出現,可將每個條件分支移入它們各自的策略類中以代替這些條件語句。
- 系統中各算法彼此完全獨立,且要求對客戶隱藏具體算法的實現細節時。
- 系統要求使用算法的客戶不應該知道其操作的數據時,可使用策略模式來隱藏與算法相關的數據結構。
- 多個類只區別在表現行爲不同,可以使用策略模式,在運行時動態選擇具體要執行的行爲。
JDK中的 ThreadPoolExecutor 中適用策略模式,有四種拒絕策略。