Skip to content

策略模式

一、介绍

策略模式(Strategy Pattern):定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换

如淘宝天猫双十一,正在搞活动有打折的、有满减的、有返利的等等,这些算法只是一种策略,并且是随时都可能互相替换的, 我们就可以定义一组算法,将每个算法都封装起来,并且使它们之间可以互换

二、应用场景

  • 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么可以使用策略模式
  • 不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法

三、角色

  • Context上下文:屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化
  • Strategy策略角色:抽象策略角色,是对策略、算法家族的抽象,定义每个策略或算法必须具有的方法和属性
  • ConcreteStrategy具体策略角色:用于实现抽象策略中的操作,即实现具体的算法

四、优缺点

  • 优点
    • 满足开闭原则,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例
    • 避免使用多重条件判断,如果不用策略模式可能会使用多重条件语句不利于维护,和工厂模式的搭配使用可以很好地消除代码if-else的多层嵌套(工厂模式主要是根据参数,获取不同的策略)
  • 缺点
    • 策略类数量会增多,每个策略都是一个类,复用的可能性很小
    • 对外暴露了类所有的行为和算法,行为过多导致策略类膨胀

五、应用

Comparator 接口常用的 compare()方法,就是一个策略设计模式的应用,把 Comparator 作为参数使用生成不同的排序策略

List<Student> list = new ArrayList<>();
list.add(new Student("a", 15));  
list.add(new Student("b", 18));  
list.add(new Student("x", 20));  


// 对伙伴的集合按年龄进行排序
Collections.sort(list, new Comparator<Student>() {

      @Override
      public int compare(Student s1, Student s2) {
        // 升序
        //return s1.getAge()-s2.getAge();
        // 降序
        // return s2.getAge()-s1.getAge();
      }
});

六、代码

策略接口类

package com.lcy.study.design.strategy;

/**
 * @Description 策略接口类
 * @Author lcy
 * @Date 2021/7/26 11:13
 */
public interface Strategy {

    /**
     * 计算价格
     * @param product 产品
     * @return double
     * @author lcy
     * @date 2021/7/26 11:26
     **/
    double computerPrice(Product product);

}

通过策略计算的对象类

package com.lcy.study.design.strategy;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * @Description 产品
 * @Author lcy
 * @Date 2021/7/26 11:25
 */
@Data
@AllArgsConstructor
public class Product {

    /**
     * 价格
     */
    private double price;

}

具体策略

package com.lcy.study.design.strategy;

import lombok.AllArgsConstructor;

/**
 * @Description 正常策略--默认
 * @Author lcy
 * @Date 2021/7/26 11:24
 */
public class NormalStrategy implements Strategy {


    @Override public double computerPrice( Product product){
        return product.getPrice();
    }
}
package com.lcy.study.design.strategy;

import lombok.AllArgsConstructor;

/**
 * @Description 抵扣策略
 * @Author lcy
 * @Date 2021/7/26 11:24
 */
@AllArgsConstructor
public class VoucherStrategy implements Strategy {

    /**
     * 抵扣的价格
     */
    private final double voucher;

    @Override public double computerPrice(Product product){
        if (product.getPrice() > voucher) {
            return product.getPrice() - voucher;
        }
        return 0;
    }
}

策略上下文类,具体执行入口

package com.lcy.study.design.strategy;

import lombok.AllArgsConstructor;

/**
 * @Description 策略上下文
 * @Author lcy
 * @Date 2021/7/26 11:29
 */
@AllArgsConstructor
public class StrategyContext {

    /**
     * 策略
     */
    private final Strategy strategy;

    /**
     * 执行策略
     * @param product 产品
     * @return double
     * @author lcy
     * @date 2021/7/26 11:31
     **/
    public double executeComputer(Product product){
        return strategy.computerPrice(product);
    }

    public static void main(String[] args){
        StrategyContext strategyContext;
        double price;
        Product product = new Product(100);

        strategyContext = new StrategyContext(new NormalStrategy());
        price = strategyContext.executeComputer(product);
        System.out.println("正常价格:" + price);


        strategyContext = new StrategyContext(new VoucherStrategy(50));
        price = strategyContext.executeComputer(product);
        System.out.println("折扣价格:" + price);
    }
}