介紹
策略模式定義了一系列算法,并將每一個(gè)算法封裝起來,而且使它們還可以相互替換箩兽。策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化
使用場景
- 針對(duì)同一類型的多種處理方式钦扭,僅僅是具體行為有差別時(shí)。
- 需要安全地封裝多種同一類型的操作時(shí)。
- 出現(xiàn)同一抽象類有多個(gè)子類,而又需要使用 if-else 或者 switch-case 來選擇具體子類時(shí)。
角色介紹
- Context——用來操作策略的上下文環(huán)境褪秀;
- Strategy——策略的抽象;
- ConcreteStrategyA薛训,ConcreteStrategyB——具體的策略實(shí)現(xiàn)媒吗。
簡單實(shí)現(xiàn)
需求:下面以坐公交工具的費(fèi)用計(jì)算來演示。
第一個(gè)版本的代碼:
public class PriceCalculator {
//公交車類型
private static final int BUS = 1;
//地鐵類型
private static final int SUBWAY = 2;
/**
* 公交車乙埃,十公里之內(nèi)一元錢闸英,超過十公里之后每加一元錢可以乘5公里
* @param km 公里
* @return
*/
private int busPrice(int km) {
//超過十公里的總距離
int extraTotal = km - 10;
//超過的距離是5公里的倍數(shù)
int extraFactor = extraTotal / 5;
//超過的距離對(duì)5公里取余
int fraction = extraTotal % 5;
//價(jià)格計(jì)算
int price = 1 + extraFactor * 1;
return fraction > 0 ? ++price : price;
}
/**
* 6公里(含)內(nèi)3元;6~12公里(含)4元膊爪;12~22公里(含)5元自阱;22~32公里(含)6元;
* @param km 公里
* @return
*/
private int subwayPrice(int km) {
if (km <= 6) {
return 3;
} else if (km <= 12) {
return 4;
} else if (km <= 22) {
return 5;
} else if (km <= 32) {
return 6;
}
//其他距離簡化為7元
return 7;
}
private int calculatePrice(int km, int type) {
if (type == BUS) {
return busPrice(km);
} else if (type == SUBWAY) {
return subwayPrice(km);
}
return 0;
}
public static void main(String[] args) {
PriceCalculator calculator = new PriceCalculator();
System.out.println("坐16公里的公交車票價(jià)為:" + calculator.calculatePrice(16, BUS));
System.out.println("坐16公里的地鐵票價(jià)為:" + calculator.calculatePrice(16, SUBWAY));
}
}
當(dāng)增加一種出行方式時(shí)米酬,如出租車沛豌,那么就需要在 PriceCalculator 中增加一個(gè)方法來計(jì)算出租車出行的價(jià)格,并且在 calculatePrice 函數(shù)中增加一個(gè)判斷,新增代碼大致如下:
public class PriceCalculator {
//公交車類型
private static final int BUS = 1;
//地鐵類型
private static final int SUBWAY = 2;
//出租車類型
private static final int TAXI = 3;
private int taxiPrice(int km) {
return km * 2;
}
private int calculatePrice(int km, int type) {
if (type == BUS) {
return busPrice(km);
} else if (type == SUBWAY) {
return subwayPrice(km);
} else if (type == TAXI) {
return taxiPrice(km);
}
return 0;
}
}
當(dāng)修改計(jì)算方式或者增加出行方式時(shí)加派,有需要增加 if-else 代碼叫确,這樣會(huì)使得代碼變得難以維護(hù)。
下面為策略模式實(shí)現(xiàn)代碼:
-
計(jì)算接口
public interface CalculateStrategy { /** * 按距離來計(jì)算價(jià)格 * @param km 公里 * @return 返回價(jià)格 */ int calculatePrice(int km); }
-
公交車價(jià)格計(jì)算策略
public class BusStrategy implements CalculateStrategy { /** * 公交車芍锦,十公里之內(nèi)一元錢竹勉,超過十公里之后每加一元錢可以乘5公里 * @param km 公里 * @return */ @Override public int calculatePrice(int km) { //超過十公里的總距離 int extraTotal = km - 10; //超過的距離是5公里的倍數(shù) int extraFactor = extraTotal / 5; //超過的距離對(duì)5公里取余 int fraction = extraTotal % 5; //價(jià)格計(jì)算 int price = 1 + extraFactor * 1; return fraction > 0 ? ++price : price; } }
-
地鐵價(jià)格計(jì)算策略
public class SubwayStrategy implements CalculateStrategy { /** * 6公里(含)內(nèi)3元;6~12公里(含)4元娄琉;12~22公里(含)5元次乓;22~32公里(含)6元; * @param km 公里 * @return */ @Override public int calculatePrice(int km) { if (km <= 6) { return 3; } else if (km <= 12) { return 4; } else if (km <= 22) { return 5; } else if (km <= 32) { return 6; } //其他距離簡化為7元 return 7; } }
-
出行計(jì)算器
public class TranficCalculator { private CalculateStrategy mStrategy; public void setStrategy(CalculateStrategy strategy) { mStrategy = strategy; } public int calculatePrice(int km) { return mStrategy.calculatePrice(km); } public static void main(String[] args) { TranficCalculator calculator = new TranficCalculator(); calculator.setStrategy(new BusStrategy()); System.out.println("公交車乘坐16公里的價(jià)格:" + calculator.calculatePrice(16)); calculator.setStrategy(new SubwayStrategy()); System.out.println("地鐵乘坐16公里的價(jià)格:" + calculator.calculatePrice(16)); }
如果需要增加一個(gè)出租車計(jì)算策略類孽水,代碼如下:
-
出租車計(jì)算策略
public class TaxiStrategy implements CalculateStrategy { @Override public int calculatePrice(int km) { return km * 2; } }
-
出行價(jià)格計(jì)算器
public class TranficCalculator { private CalculateStrategy mStrategy; public void setStrategy(CalculateStrategy strategy) { mStrategy = strategy; } public int calculatePrice(int km) { return mStrategy.calculatePrice(km); } public static void main(String[] args) { TranficCalculator calculator = new TranficCalculator(); calculator.setStrategy(new TaxiStrategy()); System.out.println("出租車乘坐16公里的價(jià)格:" + calculator.calculatePrice(16)); } }
從上面可以看出票腰,使用 if-else 來解決問題,優(yōu)點(diǎn)是實(shí)現(xiàn)簡單女气,層級(jí)單一杏慰;但缺點(diǎn)也很明顯,即代碼臃腫炼鞠,邏輯復(fù)雜缘滥,難以升級(jí)與維護(hù),沒有結(jié)構(gòu)可言谒主。
后者是通過建立抽象朝扼,將不同的策略構(gòu)建成一個(gè)具體的策略實(shí)現(xiàn),通過不同的策略實(shí)現(xiàn)算法替換瘩将。在簡化邏輯吟税、結(jié)構(gòu)的同時(shí)凹耙,增強(qiáng)了系統(tǒng)的可讀性姿现、穩(wěn)定性、可擴(kuò)展性肖抱。
Android源碼中的實(shí)現(xiàn)
TimeInterpolator 時(shí)間插值器备典,用在屬性動(dòng)畫中。
總結(jié)
- 優(yōu)點(diǎn)
- 結(jié)構(gòu)清晰明了意述,使用簡單直觀提佣;
- 耦合度相對(duì)而言較低,擴(kuò)展方便荤崇;
- 操作封裝也更徹底拌屏,數(shù)據(jù)更為安全。
- 缺點(diǎn)
- 隨著策略的增加术荤,子類也會(huì)變得繁多倚喂。