关注对象间的通信-策略模式(Strategy Pattern)
- 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换
- 淘宝天猫双十一,正在搞活动有打折的、有满减的、有返利的等等,这些算法只是一种策略,并且是随时都可能互相替换的, 我们就可以定义一组算法,将每个算法都封装起来,并且使它们之间可以互换
应用场景
- 老王计划外出旅游,选择骑自行车、坐汽车、飞机等,每一种旅行方式都是一个策略
- Java AWT中的LayoutManager,即布局管理器
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么可以使用策略模式
- 不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法
角色
- Context上下文:屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化
- Strategy策略角色:抽象策略角色,是对策略、算法家族的抽象,定义每个策略或算法必须具有的方法和属性
- ConcreteStrategy具体策略角色:用于实现抽象策略中的操作,即实现具体的算法

业务需求
老王面试进了大厂,是电商项目的营销活动组,负责多个营销活动,有折扣、优惠券抵扣、满减等,项目上线后,产品经理找茬,经常新增营销活动,导致代码改动多,加班严重搞的老王很恼火。
他发现这些都是活动策略,商品的价格是根据不同的活动策略进行计算的,因此用策略设计模式进行了优化,后续新增策略后只要简单配置就行了,不用大动干戈
代码:
抽象的接口:
public abstract class Strategy {
/**
* 根据简单订单对象,计算商品折扣后的价格
* @param productOrder
* @return
*/
public abstract double computePrice(ProductOrder productOrder);
}
具体产品:
public class ProductOrder {
private double oldPrice;
private int userId;
private int productId;
public ProductOrder(double oldPrice, int userId, int productId){
this.oldPrice = oldPrice;
this.userId = userId;
this.productId = productId;
}
public double getOldPrice() {
return oldPrice;
}
public void setOldPrice(double oldPrice) {
this.oldPrice = oldPrice;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
}
促销上下文:
public class PromotionContext {
private Strategy strategy;
public PromotionContext(Strategy strategy){
this.strategy = strategy;
}
/**
* 根据策略计算最终的价格
* @param productOrder
* @return
*/
public double executeStrategy(ProductOrder productOrder){
return strategy.computePrice(productOrder);
}
}
正常活动
public class NormalActivity extends Strategy{
@Override
public double computePrice(ProductOrder productOrder) {
return productOrder.getOldPrice();
}
}
打折活动
public class DiscountActivity extends Strategy{
/**
* 具体的折扣
*/
private double rate;
public DiscountActivity(double rate){
this.rate = rate;
}
@Override
public double computePrice(ProductOrder productOrder) {
//一系列复杂的计算
return productOrder.getOldPrice() * rate;
}
}
优惠券
public class VoucherActivity extends Strategy {
/**
* 传入优惠券
*/
private double voucher;
public VoucherActivity(double voucher){
this.voucher = voucher;
}
@Override
public double computePrice(ProductOrder productOrder) {
if(productOrder.getOldPrice() > voucher){
return productOrder.getOldPrice() - voucher;
}else {
return 0;
}
}
}
Main方法:
public class Main {
public static void main(String[] args) {
//简单订单对象
ProductOrder productOrder = new ProductOrder(800,1,33);
PromotionContext context;
double finalPrice;
//不同策略算出不同的活动价格
//没活动
context = new PromotionContext(new NormalActivity());
finalPrice = context.executeStrategy(productOrder);
System.out.println("NormalActivity = "+finalPrice);
//折扣策略
context = new PromotionContext(new DiscountActivity(0.8));
finalPrice = context.executeStrategy(productOrder);
System.out.println("DiscountActivity = "+finalPrice);
//优惠券抵扣
context = new PromotionContext(new VoucherActivity(100));
finalPrice = context.executeStrategy(productOrder);
System.out.println("VoucherActivity = "+finalPrice);
}
}
执行结果
NormalActivity = 800.0
DiscountActivity = 640.0
VoucherActivity = 700.0
优点
- 满足开闭原则,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例
- 避免使用多重条件判断,如果不用策略模式可能会使用多重条件语句不利于维护,和工厂模式的搭配使用可以很好地消除代码if-else的多层嵌套(工厂模式主要是根据参数,获取不同的策略)
缺点
- 策略类数量会增多,每个策略都是一个类,复用的可能性很小
- 对外暴露了类所有的行为和算法,行为过多导致策略类膨胀
JDK源码的应用
- Comparator 接口常用的 compare()方法,就是一个策略设计模式的应用,把 Comparator 作为参数使用生成不同的排序策略
List<Student> list = new ArrayList<>();
list.add(new Student("Anna", 15));
list.add(new Student("小D", 18));
list.add(new Student("老王", 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();
}
});
网友评论