📰 来源: 博客园
本文是【GoF设计模式】系列第14篇,更多内容欢迎关注公众号:咖啡八杯
电商网站结算时常常要算优惠:新用户满减、不同等级会员打折、节日活动满减。最直觉的写法是把所有规则塞进一个方法里用 if-else 区分:
class Cashier {
public int calc(int total, String type) {
if ("打九折".equals(type)) {
return (int) (total * 0.9);
} else if ("满300减40".equals(type)) {
return total >= 300 ? total - 40 : total;
} else {
return total;
}
}
}
这种写法很快就会失控:每加一种优惠就要往 if-else 里塞分支,Cashier 被迫认识所有规则;规则一改,核心代码跟着动。分支越堆越多,最后谁也不敢碰这块代码。
策略模式解决的就是这个"同一件事有多种做法,做法还会不断增加"的问题。把每种做法封装成独立的策略类,Cashier 只管持有策略、在结算时调用,需要哪种优惠就注入哪种,互不干扰。
策略模式(Strategy Pattern)是一种行为型设计模式,核心思想是定义一系列算法,将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户端。
这些算法完成的是相同的工作,只是实现不同。客户端在运行时选择不同的具体策略,而不必修改自身代码——新增算法只需添加新策略类,符合开闭原则。
策略模式包含三个角色:

图中各类之间的关系:ConcreteStrategyA、ConcreteStrategyB 实现 Strategy 接口,Context 持有一个 Strategy 引用,客户端面向 Context 编程——客户端和具体策略之间没有直接依赖,新增策略时 Context 无需改动。
可以把策略模式想象成餐厅点菜:顾客(客户端)跟服务员(Context)说"来一份辣的菜",服务员不自己下厨,而是把需求转交给后厨对应的厨师(具体策略)。厨师换一道菜的做法,服务员和顾客完全不用变;后厨新招一个川菜师傅(新增策略),服务员只要会喊单就行。
GoF 的标准实现中,Context 不是简单的转发层,它承担着业务数据管理和流程编排的职责。策略接口只定义纯算法契约,Context 负责将业务数据"翻译"成算法需要的参数。
// 策略接口:定义算法的公共契约
interface Strategy {
public void algorithm();
}
// 具体策略 A
class ConcreteStrategyA implements Strategy {
public void algorithm() {
System.out.println("策略 A 的算法实现");
}
}
// 具体策略 B
class ConcreteStrategyB implements Strategy {
public void algorithm() {
System.out.println("策略 B 的算法实现");
}
}
// 上下文:持有策略引用,适当时机调用策略方法
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
// Context 可以在调用策略前后做预处理/后处理
strategy.algorithm();
}
}
// 客户端代码
Context context = new Context(new ConcreteStrategyA());
context.executeStrategy(); // 使用策略 A
context.setStrategy(new ConcreteStrategyB());
context.executeStrategy(); // 切换为策略 B
实现思想:Context 持有策略引用,业务流程由 Context 编排,具体算法委托给策略执行,运行时通过 setStrategy 动态切换。
引入一个具体场景:商场收银支持无优惠、打九折、满减三种结算方式。用策略模式实现,Context 负责管理购物车和计算总价,策略只负责根据总价算优惠。
// 策略接口:根据总价计算应付金额
interface Strategy {
public int algorithm(int price);
}
// 具体策略:无优惠
class NormalStrategy implements Strategy {
public int algorithm(int price) {
return price;
}
}
// 具体策略:打九折
class DiscountStrategy implements Strategy {
public int algorithm(int price) {
return (int) (price * 0.9);
}
}
// 具体策略:满减(满100减10,满200减25,满300减40,取最大满足档位)
class FullReductionStrategy implements Strategy {
public int algorithm(int price) {
if (price >= 300) return price - 40;
if (price >= 200) return price - 25;
if (price >= 100) return price - 10;
return price;
}
}
// Context:管理购物车(数据总线)+ 计算总价(流程编排)+ 应用策略
class CashierContext {
private Strategy strategy;
private List<Integer> prices = new ArrayList<>();
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void addItem(int price) {
prices.add(price);
}
public void checkout() {
// 1. Context 负责
🔗 原文链接: 点击阅读原文
文章评论