策略模式 (Strategy)
场景问题
问题案例
考虑一个电商平台的促销活动,针对不同用户、不同时间段采用不同的折扣策略,如满减、打折、返现等。如何灵活切换和扩展这些策略?
不用模式的解决方案
实现简化版本
最直接的做法是用if-else或switch语句处理所有策略:
public class Order {
private double price;
private String type; // "discount", "cashback", "fullcut"
public Order(double price, String type) {
this.price = price;
this.type = type;
}
public double getFinalPrice() {
if ("discount".equals(type)) {
return price * 0.8;
} else if ("cashback".equals(type)) {
return price - 20;
} else if ("fullcut".equals(type)) {
return price >= 100 ? price - 30 : price;
}
return price;
}
}
使用示例
Order order = new Order(120, "discount");
System.out.println(order.getFinalPrice());
有何问题
- 策略扩展不灵活,新增策略需修改原有代码。
- 违反开闭原则,代码难以维护。
- if-else臃肿,难以阅读。
解决方案
策略模式的定义
定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。
应用策略模式的思路
- 定义统一的策略接口,各种策略实现该接口。
- 上下文对象持有策略接口引用,运行时可切换策略。
- 新增策略无需修改原有代码。
策略模式的结构
- Strategy:抽象策略,定义统一接口。
- DiscountStrategy/CashbackStrategy/FullCutStrategy:具体策略,实现不同算法。
- Context:上下文,持有策略引用,负责与客户端交互。
策略模式的实现
// 策略接口
public interface Strategy {
double calculate(double price);
}
// 具体策略
public class DiscountStrategy implements Strategy {
public double calculate(double price) { return price * 0.8; }
}
public class CashbackStrategy implements Strategy {
public double calculate(double price) { return price - 20; }
}
public class FullCutStrategy implements Strategy {
public double calculate(double price) { return price >= 100 ? price - 30 : price; }
}
// 上下文
public class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) { this.strategy = strategy; }
public double getFinalPrice(double price) {
return strategy.calculate(price);
}
}
使用示例
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setStrategy(new DiscountStrategy());
System.out.println(context.getFinalPrice(120));
context.setStrategy(new CashbackStrategy());
System.out.println(context.getFinalPrice(120));
}
}
策略重写示例
示例结构
示例代码
见上文"策略模式的实现"部分。
模式讲解
策略模式的功能
- 动态切换算法,扩展灵活。
- 满足开闭原则,便于维护。
- 代码结构清晰,易于阅读。
实现成接口
- 策略接口通常定义为接口或抽象类。
使用工厂方法
- 可结合工厂方法模式,统一创建策略对象。
切换产品簇
- 可用于切换不同的算法族,如不同促销策略。