不是所有 if-else 都该用策略模式,只有当分支 ≥ 3、逻辑复杂度接近、且基于同一行为的不同实现时,才值得重构;否则用 match、卫语句或数组映射更轻量。

直接说结论:不是所有 if-else 都该用策略模式,只有当分支 ≥ 3、逻辑复杂度接近、且基于同一行为的不同实现时,才值得重构;否则用 match、卫语句或数组映射更轻量。
什么时候该上策略模式?看这三条硬指标
策略模式不是“高级语法糖”,它解决的是「行为可插拔」问题。别一看到 if-else 就想搬策略类——先核对这三点:
- 分支是否对应同一接口的多种实现?比如都是
calculate()、export()、validate() - 分支数量是否 ≥ 3?两个分支用
match或三元足够,硬套策略反而增加调用链 - 各分支内部逻辑是否都超过 5 行、含状态校验/第三方调用/DTO 构造等?纯赋值或日志打点不配拥有策略类
常见反例:if ($status === 'pending') { $order->setStatus('processing'); } 这种单行赋值,建 PendingStatusStrategy 是在制造技术债。
PHP 8.1+ 必须用 enum + readonly 类防坑
PHP 中策略模式最容易崩在类型漂移和运行时反射滥用上。PHP 8.1 后,必须用 enum 管控策略入口,用 readonly class 锁死策略实例状态:
- 定义策略类型:用
enum PaymentMethod: string,值为Alipay、Wechat、Card,杜绝散落各处的魔法字符串 - 策略类声明为
readonly class AlipayStrategy implements PaymentStrategy,所有依赖通过构造器注入,禁止运行时修改属性 - 接口方法必须显式声明返回类型,如
public function execute(array $data): array,不能省略或写mixed,否则 PHPStan 和 IDE 会失能 - 别在工厂里用
new $className()或容器get()动态加载——这等于把if-else搬进工厂,没解耦,还引入循环依赖风险
错误示范:$strategy = match($type) { 'alipay' => new AlipayStrategy(), ... }; ——看似简洁,但破坏了类型推导,IDE 不知道 $strategy 是什么类型。
策略选择逻辑必须收在应用层,别塞进 Context
Context 类只负责执行,不负责决策。很多人把策略路由逻辑(比如根据用户等级选折扣策略)写进 OrderCalculator 的构造函数或 setStrategy(),这是错的:
- 策略选择是业务规则,属于应用层职责(Controller / Application Service),不该污染领域层的
Context - 若把选择逻辑塞进
Context,会导致测试困难:你得 mock 用户等级、配置中心、甚至数据库才能测通一个计算类 - 正确做法:Controller 根据
User::role或PaymentMethod::from($input['method'])拿到具体策略实例,再传给OrderCalculator构造器 - 这样单元测试只需传入已知策略对象,无需任何条件分支或外部依赖
顺带一提:别在策略内部用 instanceof 做二次分发,比如 if ($this instanceof AlipayStrategy) ——这等于在策略里又写了一层 if-else,彻底违背开闭原则。
比策略模式更轻量的替代方案有哪些?
策略模式是重型武器,多数场景其实不需要。以下几种更常用、更安全:
- 单层多分支:用 PHP 8.0+ 的
match表达式,类型安全、无 fallthrough、IDE 可推导返回值,比如$fee = match($method) { PaymentMethod::Alipay => 0.003, PaymentMethod::Wechat => 0.002, default => 0.005 }; - 前置校验型嵌套:用卫语句(Guard Clause)扁平化,把
if (!isValid()) { return false; }提前,主逻辑缩进归零,可读性直线上升 - 键值映射简单逻辑:用关联数组 + 匿名函数,如
$handlers = [PaymentMethod::Alipay => fn($data) => $this->doAlipay($data), ...]; $handlers[$method]($data);,适合无状态、无依赖的小逻辑
真正容易被忽略的点是:策略模式的成本不在写代码,而在后续维护者能否一眼看出「新增一种支付方式要改哪几个文件」。如果连策略枚举、接口、实现类、应用层选择逻辑这四点分散在不同目录、命名不统一、没文档说明调用链,那策略模式就只是把混乱从一个函数转移到了五个文件。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











