DesignPattern - 策略模式【行为型】
# 一、策略模式介绍
策略模式(Strategy Pattern)定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
核心组成
- Context 上下文:屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化
- Strategy 策略角色:抽象策略角色,是对策略、算法家族的抽象,定义每个策略或算法必须具有的方法和属性
- ConcreteStrategy 具体策略角色:用于实现抽象策略中的操作,即实现具体的算法
应用场景
- 外出旅游,选择骑自行车、坐汽车、飞机等,每一种旅行方式都是一个策略
- Java AWT 中的 LayoutManager(布局管理器)
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么可以使用策略模式
- 不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法
优点
- 满足开闭原则,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例
- 避免使用多重条件判断,如果不同策略模式可能会使用多重条件语句,不利于维护,和工厂模式搭配使用可以很好地消除 if-else 代码的多层嵌套(工厂模式主要是根据参数,获取不同的策略)
缺点
- 策略类数量会增多,每个策略都是一个类,复用的可能性很小
- 对外暴露了类所有的行为和算法,行为过多导致策略类膨胀
补充:JDK 中的
Collections#sort(list, comparator)
就是策略模式,比较逻辑由外部传入决定。
# 二、策略模式代码实现
以电商促销为例,一件商品,平时 800 元,赶上国庆促销,有 3 种折扣方式供用户选择:
- 不使用任何折扣
- 使用 8 折折扣
- 使用优惠券折扣
创建商品订单类:
/**
* 商品订单类
*
* @author GitLqr
*/
public class ProductOrder {
private float oldPrice;
private int userId;
private int productId;
public ProductOrder(float oldPrice, int userId, int productId) {
super();
this.oldPrice = oldPrice;
this.userId = userId;
this.productId = productId;
}
... settter & getter ...
}
创建抽象策略类,当前策略的目的就是计算出折扣后的价格:
/**
* 抽象策略角色:活动策略
*
* @author GitLqr
*/
public abstract class ActivityStrategy {
/**
* 计算订单价格
*/
public abstract double computePrice(ProductOrder productOrder);
}
创建具体策略类,对应上面的 3 种折扣方式:
/**
* 具体策略:没有活动
*
* @author GitLqr
*/
public class NormalActivityStrategy extends ActivityStrategy {
@Override
public double computePrice(ProductOrder productOrder) {
return productOrder.getOldPrice();
}
}
/**
* 具体策略:打折活动
*
* @author GitLqr
*/
public class DiscountActivityStrategy extends ActivityStrategy {
private float rate; // 折扣
public DiscountActivityStrategy(float rate) {
super();
this.rate = rate;
}
@Override
public double computePrice(ProductOrder productOrder) {
return productOrder.getOldPrice() * rate;
}
}
/**
* 具体策略:优惠券抵扣活动
*
* @author GitLqr
*/
public class VoucherActivityStrategy extends ActivityStrategy {
private float voucher;
public VoucherActivityStrategy(float voucher) {
super();
this.voucher = voucher;
}
@Override
public double computePrice(ProductOrder productOrder) {
if (productOrder.getOldPrice() > voucher) {
return productOrder.getOldPrice() - voucher;
} else {
return 0;
}
}
}
创建上下文类:
说明:对外屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化
/**
* 上下文:促销上下文
*
* @author GitLqr
*/
public class PromotionContext {
// 持有具体策略
private ActivityStrategy activityStrategy;
public PromotionContext(ActivityStrategy activityStrategy) {
super();
this.activityStrategy = activityStrategy;
}
// 直接使用具体策略进行计算
public double executeStrategy(ProductOrder productOrder) {
return activityStrategy.computePrice(productOrder);
}
}
使用:
public static void main(String[] args) {
ProductOrder productOrder = new ProductOrder(800, 9527, 1001);
PromotionContext promotionContext;
double finalPrice;
// 没活动
promotionContext = new PromotionContext(new NormalActivityStrategy());
finalPrice = promotionContext.executeStrategy(productOrder);
System.out.println("正常价:" + finalPrice);
// 打折活动
promotionContext = new PromotionContext(new DiscountActivityStrategy(0.8f));
finalPrice = promotionContext.executeStrategy(productOrder);
System.out.println("折扣价:" + finalPrice);
// 使用优惠券抵扣
promotionContext = new PromotionContext(new VoucherActivityStrategy(100));
finalPrice = promotionContext.executeStrategy(productOrder);
System.out.println("使用优惠券抵扣价:" + finalPrice);
}
- 01
- Flutter - 危!3.24版本苹果审核被拒!11-13
- 02
- Flutter - 轻松搞定炫酷视差(Parallax)效果09-21
- 03
- Flutter - 轻松实现PageView卡片偏移效果09-08