一、介紹,定義
策略模式定義了一系列的算法,並將每一個封裝起來,而且使它們可以相互替換。策略模式讓算法模式獨立於使用它的客戶而獨立變化。
二、使用場景
針對同一類型的問題的多種處理方式,僅僅是具體行爲有差別時。
需要安全地的封裝多種同一類型的操作時。
出現同一抽象類有多個子類,而又需要if-else或者switch-case來選擇具體子類時。
三、UML類圖
Context :用來操作策略的上下文環境;
Stragety:策略的抽象;
StagetyA、StagetyB:具體的策略的實現
四、簡單實現
根據公里數,計算公交車和地鐵的票價
最初版本:
public class PriceCalculator{
//公交車
private static final int BUS = 1;
//地鐵
private static final int SUBWAY = 2;
public static void main(String [] args){
PriceCalculator ca = new PriceCalcluator();
System.out.println("16公里公交票價:"+ca.calculatePrice(16,SUBWAY ));
System.out.println("16公里地鐵票價:"+ca.calculatePrice(16,BUS));
}
//十公里內1元,超過十公里後,每加一元可乘5公里
private int busPrice(int km){
int extraTotal = km-10;
int extraFactor = extraTotal/5;
int fraction = extraTotal %5'
int price = 1+extraFactor*1;
return fraction >0?++price:price;
}
//6公里內3元,6-12公里4元,12-22公里5元,22-32公里6元
private int subwayPrice(int km){
if(km<6){
return 3;
}else if(km>6&&km<12){
return 4;
}else if(km>12&&km<22){
return 5;
}else if(km>22&&km<32){
return 6;
}
return 7;//其他簡化爲7
}
int calculatePrice(int km,int type){
if(type == BUS){
return busPrice(km);
}else if(type == SUBWAY){
return subwayPrice(km);
}
return 0;
}
}
每增加一種出行方式,就要在PriceCalculator中添加一個方法計算出租車出行的價格,並在calculatePrice中添加一個判斷,各種if-else纏繞其中。下面用策略模式重構:
定義一個抽象的價格計算接口:
public interface CalculatorStrategy{
int calculatePrice(int km);
}
每種方式都實現了此接口:
public class BusStrategy implements CalculatorStrategy{
@Override
public int calculatePrice(int km){
int extraTotal = km-10;
int extraFactor = extraTotal/5;
int fraction = extraTotal %5'
int price = 1+extraFactor*1;
return fraction >0?++price:price;
}
}
public class SubwayStrategy implements CalculatorStrategy{
@Override
public int calculatePrice(int km){
if(km<6){
return 3;
}else if(km>6&&km<12){
return 4;
}else if(km>12&&km<22){
return 5;
}else if(km>22&&km<32){
return 6;
}
return 7;//其他簡化爲7
}
}
再創建一個扮演Context角色的類
public class TranficCalculator{
public static void main(String[]args){
TranficCalculator ca = new TranficCalculator();
//設置計算策略
ca.setStrategy(new BusStrategy);
//計算價格
System.out.println("16公里公交票價:"+ca.calculatePrice(16));
}
CalculatorStrategy mStrategy;
public void setStrategy(CalculatorStrategy mStrategy){
this.mStrategy = mStrategy;
}
public int calculatePrice(int km){
return mStrategy.calculatePrice(km);
}
}
這樣當我們有新的方式時,只要添加一個計算類後設置給TranficCalculator 即可。
五、模式的優缺點:
策略模式主要用來分離算法,根據相同的行爲抽象來做不同的具體策略實現。很好的實現了開閉原則,也就是定義抽象,注入具體實現,從而達到很好的可擴展性。
優點
使用了組合,使架構更加靈活
富有彈性,可以較好的應對變化(開閉原則)
更好的代碼複用性(相對於繼承)
消除大量的條件語句
缺點
隨着策略的增加,子類也會變得繁多。
選擇何種算法需要客戶端來創建對象,增加了耦合,這裏可以通過與工廠模式結合解決該問題