時勢造英雄——策略模式

HunterArley發表於2019-01-24

《Android原始碼設計模式解析與實戰》讀書筆記(七)

《Android原始碼設計模式解析與實戰》PDF資料下載

一、策略模式的簡介

1.1、定義

策略模式定義了一系列的演算法,並將每一個演算法封裝起來,而且使它們還可以相互替換。策略模式讓演算法獨立於使用它的客戶而獨立變化。

1.2、使用場景

  • 針對同一型別問題的多種處理方式,僅僅是具體行為有差別時;
  • 需要安全地封裝多種同一型別的操作時。
  • 出現同一抽象類有多個子類,而又需要使用if-else或者switch-case來選擇具體子類時。

二、策略模式的簡單實現

示例:公交車和地鐵的價格計算方式是不一樣的,需要計算乘不同出行工具的成本,下面是第一版的程式碼:

public class PriceCalculator { 
//公交車型別 private static final int BUS = 1;
//地鐵型別 private static final int SUBWAY = 2;
public static void main(String[] args) {
PriceCalculator calculator = new PriceCalculator();
System.out.println("坐16公里的公交車票價為:" + calculator.calculatePrice(16, BUS));
System.out.println("坐16公里的地鐵票價為:" + calculator.calculatePrice(16, SUBWAY));

} /** * 北京公交車,十公里之內一元錢,超過十公里之後每加一元錢可以乘5公里 * * @param km * @return */ private int busPrice(int km) {
//超過十公里的總距離 int extraTotal = km - 10;
//超過的距離是5公里的倍數 int extraFactor = extraTotal / 5;
//超過的距離對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元; * @param km * @return */ 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;

} int calculatePrice(int km, int type) {
if (type == BUS) {
return busPrice(km);

} else if (type == SUBWAY) {
return subwayPrice(km);

} return 0;

}
}複製程式碼

輸出結果:

策略模式1.png

此時的程式碼已經比較混亂,各種if-else語句纏繞其中。當價格的計算方法變化時,需要直接修改這個類中的程式碼,很容易引入錯誤。這類程式碼必然是難以應對變化的,它會使得程式碼變得越來越臃腫,難以維護。

用策略模式對上述示例進行重構:

/** * 計算介面 */public interface CalculateStrategy { 
/** * 按距離來計算價格 * @param km * @return */ int calculatePrice(int km);

}複製程式碼
//公交車價格計算策略public class BusStrategy implements CalculateStrategy { 
/** * 北京公交車,十公里之內一元錢,超過十公里之後每加一元錢可以乘5公里 * @param km * @return */ @Override public int calculatePrice(int km) {
//超過十公里的總距離 int extraTotal = km - 10;
//超過的距離是5公里的倍數 int extraFactor = extraTotal / 5;
//超過的距離對5公里取餘 int fraction = extraTotal % 5;
//價格計算 int price = 1 + extraFactor * 1;
return fraction >
0 ? ++price : price;

}
}複製程式碼
public class SubwayStrategy implements CalculateStrategy { 
@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;

}
}複製程式碼

再建立一個扮演Context角色的類

public class TranficCalculator { 
public static void main(String[] args) {
TranficCalculator calculator = new TranficCalculator();
//設定計算策略 calculator.setStrategy(new BusStrategy());
//計算價格 System.out.println("坐16公里的公交車票價為:"+calculator.calculatePrice(16));

} CalculateStrategy mStrategy;
public void setStrategy(CalculateStrategy mStrategy) {
this.mStrategy = mStrategy;

} public int calculatePrice(int km) {
return mStrategy.calculatePrice(km);

}
}複製程式碼

這種方案在隱藏實現的同時,可擴充套件性變得很強。在簡化邏輯、結構的同時,增強了系統的可讀性、穩定性、可擴充套件性,這對於較為複雜的業務邏輯顯得更為直觀,擴充套件也更為方便。

三、總結

策略模式主要用來分離演算法,在相同的行為抽象下有不同的具體實現策略。這個模式很好地演示了開閉原則,也就是定義抽象,注入不同的實現,從而達到很好的可擴充套件性。

3.1、優點

  1. 結構清晰明瞭、使用簡單直觀;
  2. 耦合度相對而言較低,擴充套件方便;
  3. 操作封裝也更為徹底,資料更為安全。

3.2、缺點

  1. 隨著策略的增加,子類也會變得繁多。

學海無涯苦作舟

我的微信公眾號

來源:https://juejin.im/post/5c49100be51d455221612e32

相關文章