策略模式

策略模式

定義

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

使用場景

  • 針對同一類型的問題的多種處理方式,僅僅是具體行爲有差異時
  • 須要安全的封裝多種同一類型的操做時候
  • 出現同一抽象類有多個子類,而又須要用if-else或switch-case來選擇具體子類時候

模式結構

  • 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能辦到的事情就不必過分設計了,不要濫用設計模式,這點好像也只能從經驗中不斷摸索了。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息