简介:设计模式知识回顾-策略模式
- 策略模式(Strategy Pattern)
- 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换
- 淘宝天猫双十一,正在搞活动有打折的、有满减的、有返利的等等,这些算法只是一种策略,并且是随时都可能互相替换的, 我们就可以定义一组算法,将每个算法都封装起来,并且使它们之间可以互换
- 应用场景
- 老王计划外出旅游,选择骑自行车、坐汽车、飞机等,每一种旅行方式都是一个策略
- Java AWT中的LayoutManager,即布局管理器
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么可以使用策略模式
- 不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法
- 对接第三方支付里面,微信支付、支付宝支付等都可以是一种策略
- 角色
- Context上下文:屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化
- Strategy策略角色:抽象策略角色,是对策略、算法家族的抽象,定义每个策略或算法必须具有的方法和属性
- ConcreteStrategy具体策略角色:用于实现抽象策略中的操作,即实现具体的算法
小例子——看结构图
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); } }
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 NormalActivity extends Strategy{ @Override public double computePrice(ProductOrder productOrder) { return productOrder.getOldPrice(); } }
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 abstract class Strategy { /** * 根据简单订单对象,计算商品折扣后的价格 * @param productOrder * @return */ public abstract double computePrice(ProductOrder productOrder); }
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; } } }
控制台输出——
- 优点
- 满足开闭原则,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例
- 避免使用多重条件判断,如果不用策略模式可能会使用多重条件语句不利于维护,和工厂模式的搭配使用可以很好地消除代码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(); } });
本文作者为DBC,转载请注明。