设计模式~策略模式

379 阅读2分钟

定义

  • 策略模式定义了一系列的算法,并将各个算法进行封装,并且在使用这些算法时可相互替换;策略模式让算法相对独立,具体使用时可独立变化

使用场景

  • 针对同一问题有多种处理方式,只是具体行为有差别
  • 出现同一抽象类的多个具体子类,代码中使用if-else来判断选择具体使用哪一种子类
  • 需要隔离封装多种实现同一类型的具体操作时

UML类图

image.png

简单实现

  • 需求:上班可以使用多种交通工具,分别计算各种交通工具的成本
  • 1.定义策略接口
/**
 * 定义计算策略
 *
 * @author LTP  2021/11/29
 */
public interface CalculateStrategy {

    /**
     * 抽象计算方法
     *
     * @param km 距离
     * @return 根据距离计算出的费用
     */
    int calculate(int km);
}
  • 2.具体策略实现策略接口
/**
 * 公交的具体计算方式
 *
 * @author LTP  2021/11/29
 */
public class BusStrategy implements CalculateStrategy {

    @Override
    public int calculate(int km) {
        // 计价规则:起步价1元(包含10km),每超过5km加收1元
        int extraKm = km - 10;
        int extraFactor = (int) Math.ceil(extraKm / 5.0);
        return 1 + extraFactor;
    }
}
/**
 * 地铁的具体计算方式
 *
 * @author LTP  2021/11/29
 */
public class SubwayStrategy implements CalculateStrategy {

    @Override
    public int calculate(int km) {
        // 计价规则:6km内(含)3元、6~12km(含)4元、12~22km(含)5元、22~32km(含)6元
        if (km <= 6) {
            return 3;
        } else if (km <= 12) {
            return 4;
        } else if (km <= 22) {
            return 5;
        } else {
            return 6;
        }
    }
}
  • 3.具体策略实现策略接口
/**
 * 策略模式具体调用类
 *
 * @author LTP  2021/11/29
 */
public class ClientCalculate {
    private CalculateStrategy calculateStrategy;

    /**
     * 设置具体的计算策略
     *
     * @param calculateStrategy 计算策略
     */
    public void setCalculateStrategy(CalculateStrategy calculateStrategy) {
        this.calculateStrategy = calculateStrategy;
    }

    public static void main(String[] args) {
        ClientCalculate clientCalculate = new ClientCalculate();
        clientCalculate.setCalculateStrategy(new BusStrategy());
        System.out.println("公交14km价格:" + clientCalculate.calculatePrice(14));

        clientCalculate.setCalculateStrategy(new SubwayStrategy());
        System.out.println("地铁12km价格:" + clientCalculate.calculatePrice(12));
    }

    /**
     * 计算交通的具体价格,交给抽象策略最终交由相应的策略来完成
     *
     * @param km 距离
     * @return 价格
     */
    private int calculatePrice(int km) {
        return calculateStrategy.calculate(km);
    }
}

image.png

应用举例

  • Android动画中的时间插值器TimeInterpolartor,默认包括线性插值器(LinearInterpolator)、加速减速插值器(AccelerateDecelerateInterpolator)以及减速插值器(DecelerateInterpolator)

优缺点

  • 优点
    • 耦合度低扩展方便
    • 封装了操作,数据安全性更高
    • 结构清晰,使用简单,易于维护
  • 缺点
    • 每增加一个策略都要增加一个实现类,使类变得繁多

与工厂模式的区别

  • 工厂模式中只管生产实例,具体怎么使用工厂实例由调用方决定,策略模式是将生成实例的使用策略放在策略类中配置后才提供给调用方使用
  • 工厂模式调用方可以直接调用工厂实例的方法属性等,策略模式不能直接调用实例的方法属性,需要在策略类中封装策略后调用