策略模式定義了一系列算法,並將每個算法封裝起來,並且他們還能夠相互替換。策略模式讓算法獨立於使用它的客戶而獨立變化。算法
Context 環境類設計模式
環境類是使用算法的角色,它在實現某個方法時能夠採起多種策略。在環境類中維護着對抽象策略類的引用。安全
Strategy 抽象策略類bash
爲所支持的算法聲明抽象方法ide
ConcreteStrategy具體策略類工具
具體實現了抽象策略類中定義的算法測試
以坐車出行爲例子,來簡單說明,假設選擇的交通工具均以路程來計價,咱們須要計算最終需支付的金額。 小A要出去玩耍,走好出門,來了輛公交車,小A果斷上去坐上了。優化
public class PriceCalculator {
public static void main(String[] args) {
PriceCalculator calculator = new PriceCalculator();
System.out.println("坐16千米公交車票價:" + calculator.busPrice(16));
}
private int busPrice(int km) {
int extraTotal = km - 10;
// 超出10km部分 每5km需額外付1元 不足5km按照5km計算
int extraFactor = extraTotal / 5;
int fraction = extraTotal % 5;
int price = 1 + extraFactor * 1;
return fraction > 0 ? ++price : price;
}
}
複製代碼
這很簡單嘛,咱們不假思索就能寫出來了。 次日,小A又要外出了,這時公交車沒有來,來了輛出租車,小A選擇了坐出租車。 也很簡單,只須要在PriceCalculator中添加一個出租車的方法就能夠了ui
public class PriceCalculator {
public static void main(String[] args) {
PriceCalculator calculator = new PriceCalculator();
System.out.println("坐16千米公交車票價:" + calculator.busPrice(16));
System.out.println("坐16千米出租車票價:" + calculator.taxiPrice(16));
}
private int busPrice(int km) {
int extraTotal = km - 10;
// 超出10km部分 每5km需額外付1元 不足5km按照5km計算
int extraFactor = extraTotal / 5;
int fraction = extraTotal % 5;
int price = 1 + extraFactor * 1;
return fraction > 0 ? ++price : price;
}
private int taxiPrice(int km) {
//10km內按起步價10元收費,超出部分每千米收費2元
if (km < 10) {
return 12;
} else {
return 16 + (km - 10) * 2;
}
}
}
複製代碼
第三天,小A想換乘地鐵了,一樣的,往PriceCalculator中添加一個乘坐地鐵的方法subPrice()便可,spa
System.out.println("坐地鐵票價:" + calculator.subPrice(16));
private int subPrice(int km) {
int extraTotal = km - 6;
int extraFactor = extraTotal / 5;
if (km < 6) {
return 3;
} else {
return 3 + extraFactor;
}
}
複製代碼
等等,這樣太麻煩了,每次調用一次出行方案,都得調用不一樣的方法,那若是方法有5個10個,那不就太混亂了?沒錯,咱們能夠用一個方法來統一管理出行方案,經過一個字段來判斷選擇哪一種出行方式啊。說幹就幹
public int calculatorPrice(int km, int type) {
if (type == BUS) {
return busPrice(km);
} else if (type == TAIX) {
return taxiPrice(km);
} else if (type == SUBWAY) {
return subPrice(km);
}
return -1;
}
複製代碼
System.out.println("坐16千米公交車票價:" + calculator.calculatorPrice(16, PriceCalculator.BUS));
System.out.println("坐16千米出租車票價:" + calculator.calculatorPrice(16, PriceCalculator.TAIX));
System.out.println("坐地鐵票價:" + calculator.calculatorPrice(16, PriceCalculator.SUBWAY));
複製代碼
如今調用起來比以前方便多了,但也使得calculatorPrice()邏輯變更比較混亂了,這時候還只有3種出行方案,若是須要添加一個新的出行方案,好比坐飛機、好比乘船、好比自駕等等,每多出一個方案就會讓這裏面的if else 變長,這會使得這個類愈來愈難以維護。更甚者,若是要取消一種出行方案,涉及到減小if else的時候,這時候就會很頭疼,由於這種類通常都會做爲公共類被調用,刪除了頗有可能對其餘地方形成影響。
那有什麼方案優化一下嗎?對於這種狀況,因爲咱們已經知道本身須要選擇的出行方案,而又但願能靈活切換所選方案的時候,就能夠考慮策略模式了。
咱們先定義一個抽象接口,用來計算價格
public interface CalculateStrategy {
/**
* 根據距離計算價格
*
* @param km 千米 路程
* @return 價格
*/
int calculatePrice(int km);
}
複製代碼
分別實現每種出行策略
public class BusStrategy implements CalculateStrategy {
@Override public int calculatePrice(int km) {
int extraTotal = km - 10;
// 超出10km部分 每5km需額外付1元 不足5km按照5km計算
int extraFactor = extraTotal / 5;
int fraction = extraTotal % 5;
int price = 1 + extraFactor * 1;
return fraction > 0 ? ++price : price;
}
}
複製代碼
public class TaxiStrategy implements CalculateStrategy{
@Override public int calculatePrice(int km) {
if (km < 10) {
return 12;
} else {
return 16 + (km - 10) * 2;
}
}
}
複製代碼
public class SubwayStrategy implements CalculateStrategy {
@Override public int calculatePrice(int km) {
int extraTotal = km - 6;
int extraFactor = extraTotal / 5;
if (km < 6) {
return 3;
} else {
return 3 + extraFactor;
}
}
}
複製代碼
建立一個扮演Context角色的環境類
public class TrafficCalculator {
CalculateStrategy mStrategy;
public void setStrategy(CalculateStrategy strategy) {
mStrategy = strategy;
}
public int calculatePrice(int km) {
return mStrategy.calculatePrice(km);
}
}
複製代碼
實現測試類
public class Test {
public static void main(String[] args) {
TrafficCalculator calculator = new TrafficCalculator();
calculator.setStrategy(new TaxiStrategy());
calculator.calculatePrice(20);
}
}
複製代碼
這樣咱們在選擇不一樣的出行方式時候,只須要經過calculator.setStrategy()方法指定對應的方式便可,其餘地方的代碼基本不須要變更,若是須要增長新的出行方案,也只須要新建一個具體策略類,而且實現CalculateStrategy接口便可。
策略模式簡化了邏輯、結構、下降了耦合性,加強了系統的可讀性、穩定性與拓展性。合理的利用策略模式,能夠有效的減小一部分if else帶來的複雜性問題。
在一些簡單狀況下,用if else能辦到的事情就不必過分設計了,不要濫用設計模式,這點好像也只能從經驗中不斷摸索了。