工厂类应通过配置或映射表驱动创建逻辑,避免硬编码和条件分支;必须返回统一接口实例以保障调用安全;优先选用可依赖注入的对象工厂,静态工厂仅适用于简单场景。

工厂类怎么写才不和具体类耦合
核心是让工厂只负责“创建”,不关心“怎么创建”。一旦工厂里出现 new MySQLConnection() 或 new RedisCache() 这种硬编码,就违背了工厂模式本意——后续加个 ElasticsearchCache 就得改工厂代码。
正确做法是用配置或映射表驱动创建逻辑:
- 把类名存在数组或配置文件里,比如
$drivers = ['mysql' => 'App\Drivers\MysqlDriver', 'redis' => 'App\Drivers\RedisDriver'] - 工厂接收一个字符串标识(如
'mysql'),查表后用new $class()或app()->make($class)实例化 - 避免在工厂方法里写
if ($type === 'mysql') { return new MysqlDriver(); }—— 这种分支越多越难维护
为什么不能直接 new 类还要绕一层工厂
不是为了炫技,而是为了解耦调用方。比如一个订单服务需要发短信,它不该知道该用阿里云还是腾讯云 SDK:
- 没工厂时:
$sms = new AliyunSmsClient($key, $secret)→ 订单服务和阿里云强绑定 - 有工厂时:
$sms = SmsFactory::make('tencent')→ 切换供应商只需改配置,订单代码零改动 - 测试也更干净:可以传入
'mock'返回一个假对象,不用动业务逻辑
注意:如果全项目就一种实现、未来也几乎不会换,那真没必要上工厂——过度设计比没设计更伤人。
立即学习“PHP免费学习笔记(深入)”;
原本这个程序只是本人两年前初学时练手的,最近拿出来进行了修改,所以叫XmxCms 企业网站管理系统2.0 开发环境:WinXP + VS2008 + SQLServer 2008 + Access开发语言:C#本程序采用 三层架构 + 抽象工厂设计模式 + Linq 实现,目前只做了Access 和 SQL Server ,默认数据库为Access,要更换数据库只需修改web.config 即可
静态工厂 vs 对象工厂怎么选
PHP 里常见两种写法,区别不在语法,在扩展性和测试性:
- 静态工厂(
SmsFactory::make('aliyun')):简单直接,但无法 mock,单元测试时很难替换行为 - 对象工厂(
$factory->make('aliyun')):可依赖注入、可继承重写、可被 PHPUnit 的createMock()拦截 - Laravel 的
Manager类(如CacheManager)就是对象工厂的典型——它靠extend()和driver()支持运行时注册新驱动
如果你的工厂要进框架容器、要支持插件式扩展,别犹豫,用对象工厂。否则静态也够用。
工厂返回的对象必须实现统一接口吗
必须。否则调用方没法安全调用方法。比如 CacheFactory::make('redis') 和 CacheFactory::make('file') 都得返回实现了 CacheInterface 的实例:
- 接口定义契约:
public function get(string $key): mixed、public function set(string $key, $value, int $ttl = 3600) - 没接口时,你只能写
if ($cache instanceof RedisCache) { ... } else if ($cache instanceof FileCache) { ... }—— 工厂的意义就塌了 - PHP 8.0+ 可用联合类型(
RedisCache|FileCache)临时过渡,但长期仍推荐接口
接口不是摆设,它是工厂能“一视同仁”对待不同实现的唯一凭据。漏掉这层,工厂就退化成一堆 new 的集合。










