工厂模式在大型项目中应避免成为新耦合点,核心是收拢创建逻辑、支持新增类型不修改调用方;需用注册表替代if链,校验交由具体类或独立函数,接口统一,配置只传逻辑名而非模块路径。

if-elif-else 创建逻辑收拢到一处,并让新增类型不碰调用方代码——但前提是工厂本身不硬编码、不越权校验、不承担本该由协议或类型系统管的事。
工厂类不该做类型判断和参数校验
常见错误是工厂里写 if handler_type == "file" + if "filename" not in kwargs。这导致每加一个新 handler,就得改工厂;而且校验逻辑和创建逻辑混在一起,违反单一职责。
- 校验应交给具体类的
__init__或独立 validator 函数,工厂只负责转发 - 类型判断推荐用注册表(字典映射),而不是 if 链:比如
cls._handlers["file"] = FileHandler - validator 可选注册,但必须是函数,不能是内联逻辑;例如
lambda k: "filename" in k,而非if ... raise块
用字典注册比继承工厂方法更轻量实用
Python 的动态性让抽象工厂/工厂方法容易过度设计。大型项目里,90% 场景用带注册能力的简单工厂就够了,比如日志后端、支付渠道、解析器选择。
- 定义统一接口(如 ABC 或 Protocol),所有产品类实现它
- 工厂暴露
register(name, creator_func, validator=None),支持运行时插件式注册 - 调用方只认
factory.create("redis"),完全不知道RedisBackend这个类名 - 避免子类爆炸:不需要为每个支付渠道写一个
AlipayFactory、WechatFactory
配置驱动创建时,别在工厂里做 import 字符串
从 YAML/JSON 加载类路径(如 "myapp.payments.AlipayClient")再用 importlib.import_module 动态导入,看似解耦,实则埋雷。
- 模块路径拼错、包未安装、循环导入,都会在
create()时才暴露,难以测试 - 推荐做法:启动时集中 import 并注册,配置只传逻辑名(如
"alipay"),不传全限定名 - 若真要动态加载,务必加缓存、加异常包装(
raise RuntimeError(f"Failed to load {path}")),别让下游处理ImportError


















