一、什么是策略模式
策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
- 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。
- 淘宝天猫双十一,正在搞活动有打折的、有满减的、有返利的等等,这些算法只是一种策略,并且是随时都可能互相替换的,我们就可以定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
二、策略模式的实现方式
模式结构分析:
- Context上下文:屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化
- Strategy策略角色∶抽象策略角色,是对策略、算法家族的抽象,定义每个策略或算法必须具有的方法和属性
- ConcreteStrategy具体策略角色:用于实现抽象策略中的操作,即实现具体的算法
类关系图:
统一模型:
代码实现:
查看代码
/*
* 具体的商品信息
* */
@Data
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 abstract class Strategy {
public abstract double computePrice(ProductOrder 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 CouponActivity extends Strategy{
private double couponPrice;
public CouponActivity(double couponPrice){
this.couponPrice = couponPrice;
}
@Override
public double computePrice(ProductOrder productOrder) {
if(productOrder.getOldPrice()>couponPrice){
return productOrder.getOldPrice()-couponPrice;
}else{
return 0;
}
}
}
/*
* 使用中这种策略的上下文
* */
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);
}
}
测试用例:
/*
* 策略模式
* */
@Test
public void strategy() {
ProductOrder productOrder = new ProductOrder(800, 1, 32);
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 CouponActivity(100));
finalPrice = context.executeStrategy(productOrder);
System.out.println("VoucherActivity ="+finalPrice);
}
测试结果:
NormalActivity =800.0
DiscountActivity =640.0
VoucherActivity =700.0
方法评估:
优点:
- 满足开闭原则,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例。
- 避免使用多重条件判断,如果不用策略模式可能会使用多重条件语句不利于维护,和工厂模式的搭配使用可以很好地消除代码if-else的多层嵌套(工厂模式主要是根据参数,获取不同的策略)。
缺点:
- 策略类数量会增多,每个策略都是一个类,复用的可能性很小
- 对外暴露了类所有的行为和算法,行为过多导致策略类膨胀