概述
- 定义了一系列的算法,并将每一个算法封装起来,使得它们可以相互替换。这种模式让算法独立于使用它的客户而变化,也就是说,客户端可以根据需要在运行时动态地改变对象的行为。
- 例如,在电商场景中,各种优惠策略(新用户折扣、满减、打折等)作为具体策略类,均实现同一策略接口;上下文为订单结算模块,根据用户类型灵活调用不同策略进行价格计算。这一模式有效增强了系统灵活性和扩展性,遵循开闭原则,易于扩展而不易修改原有代码。
核心思想
Context 上下文
:屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化
Strategy 策略角色
:抽象策略角色,是对策略、算法的抽象,定义每个策略或算法必须具有的方法和属性
ConcreteStrategy 具体策略角色
:用于实现抽象策略中的操作,即实现具体的算法
场景使用
- 计划外出旅游,选择骑自行车、坐汽车、飞机等,每一种旅行方式都是一个策略
Java AWT
中的LayoutManager
,即布局管理器
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么可以使用策略模式
- 不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法
优缺点
优点
- 满足开闭原则,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例
- 避免使用多重条件判断,如果不用策略模式可能会使用多重条件语句不利于维护,和
工厂模式的搭配
使用可以很好地消除代码if-else的多层嵌套(工厂模式主要是根据参数,获取不同的策略)
缺点
- 策略类数量会增多,每个策略都是一个类,复用的可能性很小
- 对外暴露了类所有的行为和算法,行为过多导致策略类膨胀
示例
JDK源码的应用
Student 类
java
复制代码
public class Student {
private String name;
private Integer age;
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
实现降序
java
复制代码
import net.laow.strategy.Student;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparatorTest {
@Test
public void comparatorSortTest(){
List<Student> list = new ArrayList<>();
list.add(new Student("王二", 20));
list.add(new Student("张三", 15));
list.add(new Student("李四", 18));
// 对学生的集合按年龄进行排序
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 降序
return s2.getAge()-s1.getAge();
}
});
System.out.println(list);
}
}
实现升序
java
复制代码
import net.laow.strategy.Student;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparatorTest {
@Test
public void comparatorSortTest(){
List<Student> list = new ArrayList<>();
list.add(new Student("王二", 20));
list.add(new Student("张三", 15));
list.add(new Student("李四", 18));
// 对学生的集合按年龄进行排序
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 升序
return s1.getAge()-s2.getAge();
}
});
System.out.println(list);
}
}
场景应用
需求
- 小美是电商项目的营销活动组,负责多个营销活动,有折扣、优惠券抵扣、满减等,项目上线后,产品经理找茬,经常新增营销活动,导致代码改动多,加班严重搞的小美很恼火。
- 她发现这些都是活动策略,商品的价格是根据不同的活动策略进行计算的,因此用策略设计模式进行了优化,后续新增策略后只要简单配置就行了,不用大动干戈
ProductOrder 类
java
复制代码
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;
}
}
Strategy 策略抽象
java
复制代码
public abstract class Strategy {
/**
* 根据简单订单对象,计算商品折扣后的价格
* @param productOrder
* @return
*/
public abstract double computePrice(ProductOrder productOrder);
}
PromotionContext 策略上下文
java
复制代码
public class PromotionActivity {
private Strategy strategy;
public PromotionActivity(Strategy strategy) {
this.strategy = strategy;
}
/**
* 根据策略计算最终的价格
*
* @param productOrder
* @return
*/
public double executeStrategy(ProductOrder productOrder) {
return strategy.computePrice(productOrder);
}
}
NormalActivity 无活动策略
java
复制代码
public class NormalActivity extends Strategy{
@Override
public double computePrice(ProductOrder productOrder) {
return productOrder.getOldPrice();
}
}
DiscountActivity 折扣策略
java
复制代码
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;
}
}
VoucherActivity 优惠卷策略
java
复制代码
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;
}
}
}
测试
java
复制代码
public class Main {
public static void main(String[] args) {
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 VoucherActivity(100));
finalPrice = context.executeStrategy(productOrder);
System.out.println("VoucherActivity = "+finalPrice);
}
}