当实现某功能需要根据实际情况选择不同的算法或者策略时,可以选择通过硬编码的方式(if-else 或者 switch-case)来实现,但是这样会使这个类变得臃肿,维护成本上升,出错率也变大了。基于这样的情景,如果将这些算法或者策略抽象出来,提供一个统一的接口,不同算法或者策略有不同的实现类,这样在程序客户端就可以通过注入不同的实现对象来实现算法或者策略的动态替换,这种可扩展性高、可维护性也高的模式就是策略模式。

策略模式的使用情景:

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

if-else 或者 switch-case 并不会遵循开闭原则,而应对这种情况,策略模式就能很好地解决这类问题,它将各种方案分离开来,让程序客户端根据具体的需求来动态地选择不同的策略方案。

1.策略模式

策略模式

优点

1、结构清晰,耦合度降低,扩展方便,操作封装也更为彻底,数据更为安全;

缺点

1、随着策略的增加,子类将变得繁多;

UML 类图:

策略者模式java 策略模式应用场景java_策略者模式java

Context 表示上下文,Stragety 表示策略的抽象,ConcreteStragetyA、ConcreteStragetyB 表示具体的策略实现。

1.代码实现

我们以出行旅游,选择交通工具为例,不同的出行方式(如自行车、火车、飞机)根据不同的选择价格是不一样的。

我们首先需要定义一个抽象的价格计算接口 CalculateStrategy:

public interface CalculateStrategy {
    /**
     * 按照距离来计算价格
     * @param km 公里
     * @return 返回价格
     */
    int calculatePrice(int km);
}

对于每一种出行方式我们都有独立的计算策略类:

/**
 * 自行车价格计算策略类
 */
public class BikeStrategy implements CalculateStrategy {
    @Override
    public int calculatePrice(int km) {
        // 此处省略
        return 10;
    }
}
/**
 * 火车价格计算策略类
 */
public class TrainStrategy implements CalculateStrategy {
    @Override
    public int calculatePrice(int km) {
        // 此处省略
        return 100;
    }
}
/**
 * 飞机价格计算策略类
 */
public class AircraftStrategy implements CalculateStrategy {
    @Override
    public int calculatePrice(int km) {
        // 此处省略
        return 1000;
    }
}

然后我们再创建一个扮演 Context 角色的类:

public class TranficCalculator {
    CalculateStrategy mStrategy;
    public void setStrategy(CalculateStrategy strategy) {
        mStrategy = strategy;
    }
    public int  calculatePrice(int km) {
        return mStrategy.calculatePrice(km);
    }
}

测试代码:

@Test
public void test() throws Exception {
    TranficCalculator calculator = new TranficCalculator();
    calculator.setStrategy(new TrainStrategy());
    System.out.println("price:" + calculator.calculatePrice(20));
}

输出结果: price:100

这种方案在隐藏实现的同时,可扩展性变得很强,例如,当需要增加汽车时,只需要添加一个汽车的计算策略类即可。