策略模式

定义

策略模式定义了一系列算法,并将每一个算法封装起来,而且他们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

使用场景

  • 针对同一类型的问题的多种处理方式,仅仅是具体行为有差别时
  • 需要安全的封装多种同一类型的操作时候
  • 出现同一抽象类有多个子类,而又需要用if-else或switch-case来选择具体子类时候

模式结构

  • Context 环境类

    环境类是使用算法的角色,它在实现某个方法时可以采取多种策略。在环境类中维护着对抽象策略类的引用。

  • Strategy 抽象策略类

    为所支持的算法声明抽象方法

  • 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中添加一个出租车的方法就可以了

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()即可,

    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能办到的事情就没必要过度设计了,不要滥用设计模式,这点好像也只能从经验中不断摸索了。

你可能感兴趣的:(策略模式)