工厂模式中使用Map管理策略实例时,为何仍需要Context?
·
看这篇文章前,可以先了解一下:策略模式与工厂模式的黄金组合:从设计到实战
一、核心矛盾:创建职责与调用职责的分离问题
当使用Map管理策略实例时(如Map<String, Strategy> strategyMap),工厂确实能高效获取策略实例,但这仅解决了"策略从哪里来"的问题。而策略的"如何使用"仍面临以下挑战:
- 上下文逻辑碎片化:策略调用前后的公共逻辑(如参数校验、结果处理)会散落在客户端代码中
- 调用流程不一致:不同客户端可能以不同方式调用策略,导致流程混乱
- 横切关注点泄露:非核心业务逻辑(日志、事务)污染策略接口
二、Context不可替代的三大核心价值
1. 上下文逻辑的集中封装
// 无Context时的客户端调用(反模式)
public class Client {
private final StrategyFactory factory = new StrategyFactory();
public void process(Order order) {
// 1. 前置校验(应属于上下文逻辑)
if (order.getAmount() <= 0) {
throw new IllegalArgumentException("订单金额无效");
}
// 2. 从工厂获取策略
PaymentStrategy strategy = factory.getStrategy(order.getPayType());
// 3. 执行策略(核心逻辑)
boolean result = strategy.pay(order);
// 4. 后置处理(应属于上下文逻辑)
if (result) {
order.setStatus(OrderStatus.PAID);
log.info("支付成功,订单ID:" + order.getId());
} else {
retryPayment(order); // 重试逻辑
}
}
}
2. 统一的策略调用接口
// 引入Context后的标准调用流程
public class PaymentContext {
private final StrategyFactory factory;
public PaymentContext(StrategyFactory factory) {
this.factory = factory;
}
public PaymentResult execute(Order order) {
// 1. 统一前置校验
validateOrder(order);
try {
// 2. 从工厂获取策略
PaymentStrategy strategy = factory.getStrategy(order.getPayType());
// 3. 执行策略核心逻辑
boolean payResult = strategy.pay(order);
// 4. 统一后置处理
return handlePaymentResult(order, payResult);
} catch (Exception e) {
// 5. 统一异常处理
log.error("支付异常", e);
return PaymentResult.failure(e.getMessage());
}
}
// 上下文相关的辅助方法(封装细节)
private void validateOrder(Order order) { /*...*/ }
private PaymentResult handlePaymentResult(Order order, boolean result) { /*...*/ }
}
3. 客户端代码的简化与解耦
// 客户端只需与Context交互
public class Client {
private final PaymentContext context;
public Client() {
StrategyFactory factory = new StrategyFactory();
this.context = new PaymentContext(factory);
}
public void processOrder(Order order) {
PaymentResult result = context.execute(order);
// 仅处理业务结果,无需关心调用细节
if (result.isSuccess()) {
notifyCustomer(order);
}
}
}
三、职责边界对比:工厂 vs Context vs 客户端
| 组件 | 核心职责 | 不可替代的原因 |
|---|---|---|
| 工厂 | 策略实例的创建与注册(如Map管理) | 封装对象创建逻辑,符合DRY原则 |
| Context | 策略的调用流程控制与上下文处理 | 封装公共逻辑,避免客户端重复代码 |
| 客户端 | 业务决策与结果处理 | 聚焦核心业务,不关心技术细节 |
四、UML协作图:三者的交互流程
五、典型反模式:当省略Context时的问题
- 代码重复:每个客户端都需要编写相似的校验/日志代码
- 维护困难:修改公共逻辑时需更新所有客户端
- 职责混乱:工厂被强行加入调用逻辑,违反单一职责
- 测试复杂:客户端代码包含过多技术细节,难以单元测试
六、总结:Context的本质定位
工厂是"策略对象的仓库",而Context是"策略执行的引擎"。两者结合实现:
- 技术细节封装:将策略创建、调用流程、异常处理等技术细节与业务逻辑分离
- 流程标准化:确保所有策略以统一方式被调用,降低协作成本
- 可扩展性增强:新增策略时,只需修改工厂注册逻辑,不影响调用流程
这种设计在开源框架中十分常见,例如:
- Spring的
TaskExecutor(Context)与TaskExecutorFactory(工厂) - MyBatis的
Executor(Context)与ExecutorFactory(工厂)
通过合理分离创建职责与调用职责,系统将更符合"高内聚、低耦合"的设计原则。
更多推荐


所有评论(0)