策略模式屬於對象的行爲模式。其用意是針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們可以相互替換。策略模式使得算法可以在不影響到客戶端的情況下發生變化。下面就通過一個具體的例子來演示一下:
假設現在要設計一個販賣各類書籍的電子商務網站的購物車系統。一個最簡單的情況就是把所有貨品的單價乘上數量,但是實際情況肯定比這要複雜。比如,本網站可能對所有的高級會員提供每本20%的促銷折扣;對中級會員提供每本10%的促銷折扣;對初級會員沒有折扣。
根據描述,折扣是根據以下的幾個算法中的一個進行的:
算法一:對初級會員沒有折扣。
算法二:對中級會員提供10%的促銷折扣。
算法三:對高級會員提供20%的促銷折扣。
折扣算法接口:
public interface MemberStrategy {
/**
* 計算圖書的價格
* @param booksPrice 圖書的原價
* @return 計算出打折後的價格
*/
public double calcPrice(double booksPrice);
}
初級會員折扣類:
public class PrimaryMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("對於初級會員的沒有折扣");
return booksPrice;
}
}
中級會員折扣類:
public class IntermediateMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("對於中級會員的折扣爲10%");
return booksPrice * 0.9;
}
}
高級會員折扣類:
public class AdvancedMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("對於高級會員的折扣爲20%");
return booksPrice * 0.8;
}
}
價格類:
public class Price {
//持有一個具體的策略對象
private MemberStrategy strategy;
/**
* 構造函數,傳入一個具體的策略對象
* @param strategy 具體的策略對象
*/
public Price(MemberStrategy strategy){
this.strategy = strategy;
}
/**
* 計算圖書的價格
* @param booksPrice 圖書的原價
* @return 計算出打折後的價格
*/
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}
策略選擇:
public class Client {
public static void main(String[] args) {
//選擇並創建需要使用的策略對象
MemberStrategy strategy = new AdvancedMemberStrategy();
//創建環境
Price price = new Price(strategy);
//計算價格
double quote = price.quote(300);
System.out.println("圖書的最終價格爲:" + quote);
}
}
在上面的代碼可以看出,我們的策略是折扣算法,有三種具體的實現分別有三個子類具體實現。還有一個持有策略對象的類,用於應用策略方法。客戶端只要知道需要使用的策略,創建策略的對象,調用方法就可以了。使用策略模式可以避免使用多重條件(if-else)語句。多重條件語句不易維護,它把採取哪一種算法或採取哪一種行爲的邏輯與算法或行爲的邏輯混合在一起,統統列在一個多重條件語句裏面,比使用繼承的辦法還要原始和落後。
策略模式的缺點:
(1)客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道算法或行爲的情況。
(2)由於策略模式把每個具體的策略實現都單獨封裝成爲類,如果備選的策略很多的話,那麼對象的數目就會很可觀。
總而言之,遇到某個事件,需要根據具體情況來判斷具體怎麼做,而這些做法是可以抽象出共同點的。那麼就考慮一下策略模式。而不是盲目的直接使用if-else或者switch這樣很不利於之後的擴展和維護。