-
策略模式(Strategy Pattern)
- 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换
-
应用场景
- 老王计划外出旅游,选择骑自行车、坐汽车、飞机等,每一种旅行方式都是一个策略
- Java AWT中的LayoutManager,即布局管理器
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么可以使用策略模式
- 不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法
-
角色
-
Context上下文:屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化
-
Strategy策略角色:抽象策略角色,是对策略、算法家族的抽象,定义每个策略或算法必须具有的方法和属性
-
ConcreteStrategy具体策略角色:用于实现抽象策略中的操作,即实现具体的算法
-
-
代码示例:电商优惠活动举例
/** * 订单 */ 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; } } /** * 抽象策略角色 */ abstract class Strategy { public abstract double computePrice(ProductOrder productOrder); } /** * 上下文 */ class PromotionContext { private Strategy strategy; public PromotionContext(Strategy strategy) { this.strategy = strategy; } public double executeStrategy(ProductOrder productOrder) { return strategy.computePrice(productOrder); } } /** * 不打折策略 */ class NormalActivity extends Strategy { @Override public double computePrice(ProductOrder productOrder) { return productOrder.getOldPrice(); } } /** * 折扣策略 */ 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 Main { public static void main(String[] args) { ProductOrder productOrder = new ProductOrder(100, 1, 1); PromotionContext context = new PromotionContext(new NormalActivity()); double price = context.executeStrategy(productOrder); System.out.println("不打折扣价格:" + price); PromotionContext context1 = new PromotionContext(new DiscountActivity(0.8)); double price1 = context1.executeStrategy(productOrder); System.out.println("打8折:" + price1); } }
-
优点
- 满足开闭原则,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例
- 避免使用多重条件判断,如果不用策略模式可能会使用多重条件语句不利于维护,和工厂模式的搭配使用可以很好地消除代码if-else的多层嵌套(工厂模式主要是根据参数,获取不同的策略)
-
缺点
- 策略类数量会增多,每个策略都是一个类,复用的可能性很小
- 对外暴露了类所有的行为和算法,行为过多导致策略类膨胀
-
JDK源码的应用
-
Comparator接口常用的compare()方法,就是一个策略模式的应用,把Comparator作为参数使用生成不同的排序策略
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; class Student { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public class Main { public static void main(String[] args) { Student zhangsan = new Student("张三", 18); Student lisi = new Student("李四", 55); ArrayList<Student> list = new ArrayList<>(); list.add(zhangsan); list.add(lisi); Collections.sort(list, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { // 年龄升序 //return o1.getAge()-o2.getAge(); // 年龄降序 return o2.getAge() - o1.getAge(); } }); System.out.println(list); } }
-