策略模式
一、概念
定义一系列的算法,把他们一个个封装起来,并且使他们可互相替换。本模式使得算法可独立于使用它的客户而变化。
二、使用场景
一个类定义了多种行为,并且这些行为在这个类的方法中以多个条件语句的形式出现,那么可以使用策略模式避免在类中使用大量的条件语句。
三、UML结构图

通过一个持有算法的Context上下文对象,来封装一系列的算法。
Context对象并不负责具体决定哪个算法,而是把算法选择工作交给了Client端,Client端可以选择好具体的算法,把其设置到上下文对象中,让上下文对象持有客户端所选择的具体的策略。
当客户端通知Context类去执行某项他想要的业务功能时,Context类就会转到具体的算法中。
四、代码示例
1.不使用策略模式的代码及弊端:
PriceCalculator:
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("20km公交票价:"+calculator.calculatePrice(20,BUS));
System.out.println("20km地铁票价:"+calculator.calculatePrice(20,SUBWAY));
}
/**
* 公交车计价 10km之内1块钱;
* 超过10km,每加一块钱可以乘5km
* @param km
* @return
*/
private int busPrice(int km){
//超过10km的距离
int extraTotal = km - 10;
//超过距离是5km的倍数
int extraFactor = extraTotal / 5;
//超过的距离对5km取余
int fraction = extraTotal % 5;
//计算价格
int price = 1 + extraFactor % 5;
return fraction > 0? ++price : price;
}
/**
* 地铁计价 : 6-12km:4块 ;12-22km:5块; 22-32km:6块;其他距离7块
* @param km
* @return
*/
public 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;
}
/**
* 根据不同类型方式计价
* @param km
* @param type
* @return
*/
int calculatePrice(int km,int type){
if(type == BUS){
return busPrice(km);
}else if(type == SUBWAY){
return subwayPrice(km);
}
return 0;
}
}
弊端:
PriceCalculator 类很明显的一个问题就是不是单一职责,首先它承担计算公交和地铁乘坐价格的职责;另一个问题是通过if-else的形式来判断使用哪种计算形式,当增加一种出行方式时,如出租车,那么就需要在PriceCalculator中增加一个方法来计算出租车出行的价格,并且在calculatePrice(int km,int type)函数增加一个判断。
此种情况下,如果要增加一个出租车的类型时:
private static final int TAXI = 3;
private int taxiPrice(int km){
return km * 2;
}
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;
}
2.使用策略模式实现:
AbstractStrategy:
public interface AbstractStrategy {
//按距离计算价格
int calculatePrice(int km);
}
BusStrategy:
public class BusStrategy implements AbstractStrategy{
@Override
public int calculatePrice(int km) {
//超过10km的距离
int extraTotal = km - 10;
//超过距离是5km的倍数
int extraFactor = extraTotal / 5;
//超过的距离对5km取余
int fraction = extraTotal % 5;
//计算价格
int price = 1 + extraTotal % 5;
return fraction > 0 ? ++price : price;
}
}
SubwayStrategy:
public class SubwayStrategy implements AbstractStrategy{
@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;
}
}
TaxiStrategy:
public class TaxiStrategy implements AbstractStrategy{
@Override
public int calculatePrice(int km) {
return km * 2;
}
}
Context:
public class Context {
//持有抽象接口的引用
private AbstractStrategy strategy;
//把抽象引用作为参数传进来
public void setStrategy(AbstractStrategy strategy){
this.strategy = strategy;
}
public int calculatePrice(int km){
return strategy.calculatePrice(km);
}
public static void main(String[] strings){
Context calculator = new Context();
//只需要在客户端动态的传入类型,而不需要更改管理类
//calculator.setStrategy(new BusStrategy());
calculator.setStrategy(new TaxiStrategy());
System.out.println("公交车20km价格:"+calculator.calculatePrice(20));
}
}
五、策略模式的优点
- 上下文(Context)和具体策略(ConcreteStrategy)是松耦合关系。
- 策略模式满足“开-闭原则”
网友评论