策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
策略模式
1 概述
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。下面就以一个示意性的实现讲解策略模式实例的结构。
结构
这个模式涉及到三个角色:
- 环境(Context)角色:持有一个Strategy的引用。
- 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
- 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
策略模式的使用场景:
1)针对同一种问题的多种处理方式、仅仅是因为具体行为有差别时,
2)需要安全的封装多种同一类型的操作时
3)出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时。
2 引入
计算公交车和地铁运行指定路程后所需的票价
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| 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("坐10公里的公交车的票价为:" + calculator.calculatePrice(10, BUS)); System.out.println("坐10公里的地铁的票价为:" + calculator.calculatePrice(10, SUBWAY));
} private int busPrice(int km) { int extraTotal = km - 10; int extraFactor = extraTotal / 5; int fraction = extraTotal % 5; int price = 1 + extraFactor * 1; return fraction > 0 ? ++price : price; }
private int subwayPrice(int km) { if (km <= 6) { return 3; } else if (km > 6 && km < 12) { return 4; } else if (km < 22 && km > 12) { return 5; } else if (km < 32 && km > 22) { return 6; } return 7; }
private int calculatePrice(int km, int type) { if (type == BUS) { return busPrice(km); } else { return subwayPrice(km); } } }
|
如果再添加一种出租车的价格计算,添加相应的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class PriceCalculator { private static final int BUS = 1; private static final int SUBWAY = 2;
private static final int TAXI = 3;
public static void main(String[] args) { PriceCalculator calculator = new PriceCalculator(); System.out.println("坐10公里的公交车的票价为:" + calculator.calculatePrice(10, BUS)); System.out.println("坐10公里的地铁的票价为:" + calculator.calculatePrice(10, SUBWAY));
}
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 { return taxiprice(km); } } }
|
可见上面的代码耦合性较高,每当增加新的交通工具类型的时候,需要不断的修改大量的代码,这里使用策略模式重构:
3 示例
首先定义一个抽象的价格计算接口:
1 2 3 4
| public interface CalculateStrategy { int calculatePrice(int km); }
|
每一种出行方式都定义一个独立的计算策略类:
公交车计算策略
1 2 3 4 5 6 7 8 9
| public class BusStrategy implements CalculateStrategy { public int calculatePrice(int km) { int extraTotal = km - 10; int extraFactor = extraTotal / 5; int fraction = extraTotal % 5; int price = 1 + extraFactor * 1; return fraction > 0 ? ++price : price; } }
|
地铁计算策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class SubwayStrategy implements CalculateStrategy {
public int calculatePrice(int km) { if (km <= 6) { return 3; } else if (km > 6 && km < 12) { return 4; } else if (km < 22 && km > 12) { return 5; } else if (km < 32 && km > 22) { return 6; } return 7; } }
|
再创建一个扮演Context的角色,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class TranficCalculator { CalculateStrategy mStrategy; public static void main(String[] args) { TranficCalculator calculator = new TranficCalculator(); calculator.setStrategy(new BusStrategy()); System.out.println("公交车乘10公里的价格:" + calculator.calculatePrice(10)); } public void setStrategy(CalculateStrategy mStrategy) { this.mStrategy = mStrategy; } public int calculatePrice(int km) { return mStrategy.calculatePrice(km); } }
|
这样即使需要添加出租车的价格计算,只需要简单的新建一个类,让其继承自CalculateStrategy接口并实现其中的方法即可
4 优缺点
优点
1)结构清晰明了、使用简单直观
2)耦合度相对较低,扩展方便
3)操作封装因为更为测地、数据更为安全
缺点
子类增多
参考链接