抽象工厂模式解决成套创建一组相关或相互依赖对象的问题,如MySQL连接、语句处理器与事务管理器的协同创建,避免客户端硬编码具体类名,实现产品族的封装与解耦。

抽象工厂模式解决什么问题
当项目里需要成套创建一组相关或相互依赖的对象(比如 MySQL 连接 + MySQL 语句处理器 + MySQL 事务管理器),又不想让客户端代码硬编码具体类名时,Abstract Factory 就是比简单工厂更合适的解法。它不只封装“单个对象怎么造”,而是封装“一整套产品怎么协同造出来”。
为什么不能只用简单工厂
简单工厂(如 LoggerFactory::create('file'))在新增一个数据库类型时,往往要改 switch 分支、加新 if、引入新类——违反开闭原则。而抽象工厂把“MySQL 一族”和“PostgreSQL 一族”的创建逻辑完全隔离,新增数据库支持只需新增一个具体工厂类,不碰原有代码。
- 简单工厂返回的是单个对象,抽象工厂返回的是多个协作对象组成的接口族
-
AbstractFactory接口定义方法签名(如createConnection(),createStatement()),每个具体工厂实现这些方法,但内部 new 的全是对应厂商的类 - 客户端只依赖
AbstractFactory和各产品接口(如Connection,Statement),完全不知道 MySQL 或 PDO 的存在
PHP 中抽象工厂的关键实现细节
PHP 没有接口多继承,所以得靠组合+类型约束来保证产品族一致性。常见错误是让工厂返回 object 或未声明返回类型,导致 IDE 无法提示、运行时才报错。
- 每个产品必须定义接口(如
ConnectionInterface,StatementInterface),不能直接返回具体类 - 抽象工厂本身是接口(
DatabaseFactoryInterface),不是抽象类——PHP 接口更轻量,也避免单继承限制 - 具体工厂(如
MySqlFactory)必须严格返回本族全部产品,且类型与接口一致;否则调用方拿到MySqlStatement却想调用PgsqlStatement特有方法,会出错 - 别在工厂里做连接初始化(如
new PDO(...))——连接建立应延迟到ConnectionInterface::connect()被调用时,否则工厂变重、难测试
容易被忽略的维护陷阱
抽象工厂真正起效的前提,是产品接口设计足够稳定。一旦 ConnectionInterface::beginTransaction() 要加第三个参数,所有已实现该接口的类(MySQL、SQLite、PgSQL)都得改,整个产品族就断了。
立即学习“PHP免费学习笔记(深入)”;
- 接口变更成本远高于类内部修改,定义前务必确认核心行为契约是否真的通用
- 不要为“可能扩展”提前抽象——比如当前只有 MySQL 和 SQLite,就先写两个具体工厂;等 PgSQL 真实接入再抽
AbstractFactory,过早抽象反而增加理解负担 - 工厂类本身不该持有配置(如 host/user/pass),这些应通过构造函数注入,否则工厂职责混乱,也妨碍单元测试中替换 mock 工厂



















