当if-else分支超5个、逻辑重复、需动态切换且难测试扩展时,应改用策略模式;核心是定义统一策略接口并让各分支实现为独立类,通过注册表+工厂解耦查找,注意构造参数、异常处理、共享逻辑复用及契约文档化。

什么时候该用策略模式替代 if-else
当你的 if-else 链开始出现重复判断逻辑、分支越来越多(比如超过 5 个)、每个分支内部有独立的数据处理步骤,且这些分支未来可能新增或动态切换时,就该考虑策略模式了。硬编码的 if-else 很难测试、难扩展,也容易在修改一个分支时误伤其他分支。
典型场景包括:支付方式路由(alipay / wechat_pay / paypal)、报表导出格式(csv / excel / pdf)、风控规则引擎中的不同校验策略。
怎么定义策略接口和具体策略类
核心是把每个 if 分支抽象成一个独立类,它们实现统一接口。Python 没有 interface 关键字,用抽象基类(ABC)或仅靠约定(duck typing)都行,推荐前者——更明确、IDE 支持好、运行时能报错。
示例中,假设你原来有一段根据 payment_type 字符串做分支的代码:
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
if payment_type == "alipay":
result = alipay_process(order)
elif payment_type == "wechat_pay":
result = wechat_process(order)
elif payment_type == "paypal":
result = paypal_process(order)
重构后:
- 定义抽象策略类
PaymentStrategy,含抽象方法process() - 每个具体策略继承它,实现自己的
process(),不依赖外部条件判断 - 策略类里只放和本策略强相关的逻辑,比如
AlipayStrategy只管签名、调用支付宝 SDK,不碰微信的参数
如何避免策略注册和查找时的硬编码
手动写一堆 if strategy_name == "xxx": return XxxStrategy() 只是把 if-else 搬到了别处,没解决问题。要用注册表 + 工厂模式解耦:
- 用字典
_strategies存储{"alipay": AlipayStrategy, "wechat_pay": WechatStrategy},键是策略标识(通常来自配置或请求参数) - 提供
get_strategy(name)方法,查不到时抛ValueError,而不是静默返回默认值——这会让问题暴露得更早 - 注册可放在模块加载时(用
@register_strategy("alipay")装饰器),也可集中初始化,避免散落在各处 - 别把策略实例缓存成单例除非它真无状态;有用户上下文、临时数据的策略,每次应新建实例
策略模式下容易被忽略的边界问题
很多人以为策略一换就万事大吉,但实际落地时几个点常被跳过:
-
__init__参数不一致:有的策略需要api_key,有的要timeout,统一构造函数签名或用**kwargs接收,再由子类校验 - 异常处理粒度:是让每个策略自己捕获并转成统一错误,还是由上下文统一兜底?推荐前者——策略最清楚自己可能抛什么,比如
PaypalStrategy应把PayPalAPIError转成PaymentFailedError - 策略间共享逻辑(如日志、埋点)别重复写,抽成基类方法或用装饰器,但别因此引入新耦合
- 测试时别只测 happy path:故意传错
strategy_name,验证是否报明确错误;模拟某个策略抛异常,看上层能否正确降级
策略模式不是银弹——如果只有两个分支、逻辑极其简单,强行套用反而增加理解成本。关键是判断“复杂度是否已溢出”。真正麻烦的从来不是模式本身,而是策略之间的隐式契约:输入格式、输出结构、失败语义,这些必须文档化或用类型提示(def process(self, order: Order) -> PaymentResult:)固化下来。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










