策略模式
一、介绍
策略模式(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);
}
}