每天认识一种设计模式之工厂方法模式
1. 模式定义
工厂方法模式属于创建型设计模式,核心思想是将对象的创建过程延迟到子类,通过定义接口让子类决定实例化哪个具体类,实现创建逻辑与使用逻辑的解耦。
2. 核心结构
- 产品接口(Product Interface):定义对象的公共方法
- 具体产品(Concrete Products):实现接口的具体类
- 创建者抽象类(Creator):声明工厂方法(可含默认实现)
- 具体创建者(Concrete Creators):实现工厂方法,返回具体产品
3. 应用场景
- 跨平台对象创建(如不同 UI 控件生成)
- 数据库连接器适配(MySQL、PostgreSQL 等)
- 日志记录器选择(文件日志、数据库日志)
- 需要动态扩展产品类型时(符合开闭原则)
4. 场景特点
需要灵活扩展产品类型,且不同产品由不同子类负责创建。
PHP 代码示例
场景:支付网关处理器(支付宝、微信支付)
代码语言:php复制<?php
// -------------------- 产品接口 --------------------
interface PaymentGateway {
public function pay(float $amount): string;
}
// -------------------- 具体产品 --------------------
class Alipay implements PaymentGateway {
public function pay(float $amount): string {
return "支付宝支付成功:¥" . $amount;
}
}
class WechatPay implements PaymentGateway {
public function pay(float $amount): string {
return "微信支付成功:¥" . $amount;
}
}
// -------------------- 创建者抽象 --------------------
abstract class PaymentFactory {
// 工厂方法(核心)
abstract public function createPayment(): PaymentGateway;
// 可包含通用业务逻辑
public function processOrder(float $amount): string {
$payment = $this->createPayment();
return $payment->pay($amount);
}
}
// -------------------- 具体创建者 --------------------
class AlipayFactory extends PaymentFactory {
public function createPayment(): PaymentGateway {
return new Alipay();
}
}
class WechatPayFactory extends PaymentFactory {
public function createPayment(): PaymentGateway {
return new WechatPay();
}
}
// -------------------- 客户端使用 --------------------
function clientCode(PaymentFactory $factory, float $amount) {
echo $factory->processOrder($amount) . PHP_EOL;
}
// 使用支付宝
clientCode(new AlipayFactory(), 100.50);
// 使用微信支付
clientCode(new WechatPayFactory(), 200.00);
/* 输出:
支付宝支付成功:¥100.5
微信支付成功:¥200
*/
模式优势
优势 | 说明 |
---|---|
解耦创建逻辑 | 客户端只需与抽象接口交互 |
符合开闭原则 | 新增支付方式无需修改现有代码 |
代码可维护性高 | 创建逻辑集中管理 |
支持多态扩展 | 可结合配置系统动态选择支付方式 |
对比简单工厂模式
特性 | 工厂方法模式 | 简单工厂模式 |
---|---|---|
扩展性 | 通过子类扩展(无需修改父类) | 需要修改工厂类逻辑 |
符合开闭原则 | ✅ 是 | ❌ 否 |
结构复杂度 | 较高(需要继承体系) | 较低(单一工厂类) |
适用场景 | 需要频繁扩展产品类型 | 产品类型固定且较少 |
实际开发建议
- 预判扩展需求:当预计会有多种同类对象需要创建时使用
- 结合依赖注入:通过容器绑定具体工厂实现
- 避免过度设计:简单场景可直接使用
if/switch
简单工厂 - 单元测试优势:可 Mock 工厂方法返回测试对象