策略模式其實一直在用,只是你不知道你用的 就是策略模式。
是面向接口編程的典型設計模式。
該模式可以解決在不同算法實現時使用if..else帶來的複雜和難以維護,完全實現接口該詞的理念,無縫插拔,降低耦合度。
模擬場景、問題提出
假設現在有一個場景,雙十一賣書促銷,普通遊客打98折,會員打9折,plus會員打8折。那最簡單的寫法如下:
public class Price {
public double price(String userType, double productPrice) {
if ("遊客".equals(userType)) {
return productPrice * 0.98;
} else if ("會員".equals(userType)) {
return productPrice * 0.9;
} else if ("plus會員".equals(userType)) {
return productPrice * 0.8;
}
return productPrice;
}
}
但這樣會帶來什麼問題?
- 該方法一大坨代碼摻雜了太多種類的計算方式,稍不留神就會出錯;
- 過多的if..else使代碼難以維護;
- 若有折扣變動或用戶種類增多,會使本就一大坨的代碼變成更大的一坨;且需要修改已有的代碼,造成未知錯誤。
引入策略模式
策略模式可以有效解決上述問題,做到易維護、可擴展。
策略模式定義:
定義一系列的算法,把他們一個個封裝起來,並且使他們可相互替換。
爲了使價格計算方式算法獨立於用戶類型 ,需要專門有一個上下文類Context持有算法,但不決定使用哪個算法,將決定權交於用戶;由用戶選擇好具體算法後,設置到上下文中;當用戶通知上下文執行功能時,即根據選擇執行具體的算法。
這樣可以使用戶與具體算法分離
- 算法可獨立於用戶變化
- 用戶可動態切換需要使用的算法
策略模式實例代碼
下面我將創建一個Strategy接口,然後分別用3個類使用不同的算法實現該接口中的price(計算價格)方法;然後Context類是一個上下文類,調用他的某個參數決定其使用哪個策略;最終通過Test類根據不同的入參調用策略類得到不同的策略執行結果。
首先創建Strategy接口,該接口只有一個方法price():
/**
* 策略接口
*/
public interface Strategy {
/**
* 計算價格
*/
public double price(double productPrice);
}
然後創建3個類實現該接口,並用不同的算法實現price()方法,分別代表三類用戶,返回不同的折扣結果,若調用則會輸出不同的運行結果:
/**
* 普通遊客
*/
public class StrategyNormalUser implements Strategy {
@Override
public double price(double productPrice) {
return productPrice * 0.98;
}
}
/**
* vip用戶
*/
public class StrategyVipUser implements Strategy {
@Override
public double price(double productPrice) {
return productPrice * 0.9;
}
}
/**
* plus_vip用戶
*/
public class StrategyPlusVipUser implements Strategy {
@Override
public double price(double productPrice) {
return productPrice * 0.8;
}
}
新建一個Context類,引入strategy變量,並新增contextExecute方法,該方法會調用Strategy接口中的price()方法
/**
* 上下文類
*/
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public double contextExecute(double productPrice) {
return this.strategy.price(productPrice);
}
}
開始測試,在Test類中調用Context的構造方法,直接將不同的Strategy子類給strategy賦值,然後調用contextExecute方法,內部繼續調用子類的price方法,得到不同的運算結果。當想更換用戶時,只需要在12行創建Strategy策略對象時,將不同的子類傳入構造器,就改這一行,是不是 簡單清晰?
/**
* 測試類
*/
public class Test {
// 原始價格
final static double PRODUCT_PRICE = 100.00;
public static void main(String[] args) {
// 1、選擇並創建需要使用的策略對象
Strategy strategy = new StrategyNormalUser();
// Strategy strategy = new StrategyVipUser();
// Strategy strategy = new StrategyPlusVipUser();
// 2、創建上下文對象
Context context = new Context(strategy);
// 3、計算價格
System.out.println("折扣後的價格爲:" + context.contextExecute(PRODUCT_PRICE));
}
}
運行結果:
上述操作流程圖: