PHP 工厂模式

概述

工厂模式(Factory Method Pattern)又称“工厂方法”,是创建型设计模式的核心成员,也是对简单工厂模式的优化升级。其核心目标是将对象创建逻辑延迟到子类,通过定义一个创建对象的抽象接口(工厂接口/抽象工厂类),由子类决定具体实例化哪一个产品类,实现“开放-封闭原则”,解决简单工厂模式中新增产品需修改工厂类的问题。

核心价值

  • 遵循开闭原则:新增产品时无需修改原有工厂逻辑,仅需新增对应产品类和工厂子类,扩展性更强;

  • 解耦更彻底:抽象工厂与抽象产品对应,客户端仅依赖抽象层,不依赖具体实现,降低代码耦合度;

  • 职责单一化:每个工厂子类仅负责创建一种产品,工厂逻辑清晰,便于维护和迭代;

  • 灵活性提升:支持动态切换产品实现,客户端可通过替换工厂子类,切换不同的产品实例。

适用场景

  • 产品类数量较多且可能持续扩展(如超过5个同类产品),需避免修改原有工厂逻辑;

  • 客户端不关心产品创建细节,仅需通过工厂获取产品,且需支持产品动态切换;

  • 产品类具有共同的父类或实现统一接口,工厂类也遵循统一的抽象接口。

注意事项

  • 类数量增加:每新增一个产品,需同时新增对应的工厂子类,可能导致类数量膨胀(trade-off 为扩展性);

  • 避免过度设计:若产品变动极少,简单工厂模式更简洁,无需引入抽象工厂和多个子类;

  • 依赖抽象:客户端必须依赖抽象工厂和抽象产品,而非具体实现,否则失去解耦意义。

完整代码

<?php
declare(strict_types = 1);

/**
 * 产品接口:定义所有产品的统一规范
 * Interface ProductInterface
 */
interface ProductInterface
{
    public function doService(): string;
}

/**
 * 具体产品A:支付宝支付(实现产品接口)
 * Class AlipayProduct
 */
class AlipayProduct implements ProductInterface
{
    public function doService(): string
    {
        return "支付宝支付:执行订单扣款、回调通知逻辑";
    }
}

/**
 * 具体产品B:微信支付(实现产品接口)
 * Class WechatPayProduct
 */
class WechatPayProduct implements ProductInterface
{
    public function doService(): string
    {
        return "微信支付:执行订单预支付、支付结果校验逻辑";
    }
}

/**
 * 抽象工厂接口:定义工厂的统一规范(创建产品的接口)
 * Interface FactoryInterface
 */
interface FactoryInterface
{
    public function createProduct(): ProductInterface;
}

/**
 * 具体工厂A:支付宝工厂(负责创建支付宝产品实例)
 * Class AlipayFactory
 */
class AlipayFactory implements FactoryInterface
{
    public function createProduct(): ProductInterface
    {
        // 可添加产品初始化逻辑(如加载支付宝配置、初始化客户端)
        $this->initAlipayConfig();
        return new AlipayProduct();
    }

    // 支付宝专属初始化逻辑
    private function initAlipayConfig(): void
    {
        // 模拟加载配置:如APP_ID、私钥、公钥等
        // $config = require_once 'alipay_config.php';
    }
}

/**
 * 具体工厂B:微信支付工厂(负责创建微信支付产品实例)
 * Class WechatPayFactory
 */
class WechatPayFactory implements FactoryInterface
{
    public function createProduct(): ProductInterface
    {
        // 微信支付专属初始化逻辑(如加载证书、初始化SDK)
        $this->initWechatPayConfig();
        return new WechatPayProduct();
    }

    // 微信支付专属初始化逻辑
    private function initWechatPayConfig(): void
    {
        // 模拟加载配置:如APP_ID、商户号、API密钥等
        // $config = require_once 'wechatpay_config.php';
    }
}

// 测试代码
try {
    // 1. 使用支付宝工厂创建支付宝产品
    $alipayFactory = new AlipayFactory();
    $alipay = $alipayFactory->createProduct();
    echo $alipay->doService() . PHP_EOL; // 输出:支付宝支付:执行订单扣款、回调通知逻辑

    // 2. 使用微信支付工厂创建微信支付产品
    $wechatPayFactory = new WechatPayFactory();
    $wechatPay = $wechatPayFactory->createProduct();
    echo $wechatPay->doService() . PHP_EOL; // 输出:微信支付:执行订单预支付、支付结果校验逻辑

    // 3. 客户端可动态切换工厂(如切换支付方式)
    $payFactory = new AlipayFactory(); // 可根据配置动态选择工厂
    $payProduct = $payFactory->createProduct();
    echo $payProduct->doService() . PHP_EOL;
} catch (\Exception $e) {
    echo "错误:" . $e->getMessage();
}

核心设计说明

1. 核心结构拆解

// 1. 产品接口:定义所有产品的统一方法,保证产品一致性
interface ProductInterface
{
    public function doService(): string;
}

// 2. 具体产品类:实现产品接口,封装自身业务逻辑(可包含专属属性/方法)
class AlipayProduct implements ProductInterface
{
    public function doService(): string { /* 业务逻辑 */ }
}

// 3. 抽象工厂接口:定义创建产品的统一方法,规范工厂行为
interface FactoryInterface
{
    public function createProduct(): ProductInterface;
}

// 4. 具体工厂类:实现抽象工厂接口,负责对应产品的创建和初始化
class AlipayFactory implements FactoryInterface
{
    public function createProduct(): ProductInterface
    {
        // 产品专属初始化逻辑
        return new AlipayProduct();
    }
}

2. 关键优化点(对比基础实现)

// 优化1:引入抽象工厂接口,强制所有工厂遵循统一规范,便于客户端调用
interface FactoryInterface
{
    public function createProduct(): ProductInterface;
}

// 优化2:具体工厂封装产品专属初始化逻辑,职责单一且内聚
private function initAlipayConfig(): void
{
    // 产品初始化逻辑(如加载配置、初始化依赖),不暴露给客户端
}

// 优化3:明确类型声明(返回值为 ProductInterface),增强类型安全和可读性
public function createProduct(): ProductInterface

// 优化4:遵循开闭原则,新增产品无需修改原有工厂,仅需扩展子类
// 新增产品C(ApplePay)时,仅需新增 ApplePayProduct 和 ApplePayFactory

// 优化5:客户端依赖抽象层,可通过切换工厂子类动态切换产品,灵活性更强
$payFactory = new AlipayFactory(); // 切换为 WechatPayFactory 即可换产品

3. 常见错误规避

// 错误1:未定义抽象工厂接口,直接创建具体工厂,客户端依赖具体实现,耦合度高
// 解决:定义 FactoryInterface,所有具体工厂实现该接口

// 错误2:具体工厂包含多种产品创建逻辑,违背单一职责原则
// 解决:一个具体工厂仅负责一种产品的创建,新增产品对应新增工厂

// 错误3:产品类无统一接口,工厂返回不同类型产品,客户端调用混乱
// 解决:强制所有产品实现 ProductInterface,工厂统一返回该接口类型

// 错误4:将产品初始化逻辑放在客户端,导致客户端与产品耦合
// 解决:将初始化逻辑封装在具体工厂中,客户端仅调用工厂的 createProduct() 方法

补充说明

1. 扩展场景示例(新增产品)

若需新增 ApplePay 支付产品,仅需扩展两个类,无需修改原有代码,完全遵循开闭原则:


// 1. 新增具体产品类(实现产品接口)
class ApplePayProduct implements ProductInterface
{
    public function doService(): string
    {
        return "ApplePay支付:执行生物识别验证、支付扣款逻辑";
    }
}

// 2. 新增具体工厂类(实现工厂接口)
class ApplePayFactory implements FactoryInterface
{
    public function createProduct(): ProductInterface
    {
        // ApplePay专属初始化逻辑(如加载证书、初始化SDK)
        $this->initApplePayConfig();
        return new ApplePayProduct();
    }

    private function initApplePayConfig(): void
    {
        // 模拟加载ApplePay配置
    }
}

// 客户端使用(无需修改原有代码)
$applePayFactory = new ApplePayFactory();
$applePay = $applePayFactory->createProduct();
echo $applePay->doService();

2. 实际应用场景

  • 多支付方式集成(支付宝/微信/ApplePay/银行卡),支持动态切换;

  • 日志驱动扩展(文件日志/数据库日志/Redis日志/ELK日志);

  • 缓存适配器管理(本地缓存/Redis缓存/Memcached缓存);

  • 消息推送渠道(短信/邮件/微信公众号/APP推送)。

简单工厂模式与工厂模式对比表

对比维度 简单工厂模式 工厂模式(工厂方法)
核心结构 一个静态工厂类 + 多个具体产品(无抽象工厂) 抽象工厂接口 + 多个具体工厂 + 多个具体产品(一对一对应)
开闭原则 不遵循:新增产品需修改工厂类的判断逻辑(如添加case分支) 遵循:新增产品仅需扩展具体产品和工厂子类,无需修改原有代码
类数量 少:仅需1个工厂类,产品类按需增加 多:每新增1个产品,需对应新增1个工厂子类,可能导致类膨胀
创建逻辑位置 集中在一个工厂类中,由工厂根据参数判断创建哪种产品 分散在各个具体工厂中,每个工厂仅负责创建一种产品,无判断逻辑
客户端依赖 依赖具体工厂类和抽象产品(或具体产品) 仅依赖抽象工厂和抽象产品,完全解耦具体实现
灵活性 较低:切换产品需修改客户端传入的参数,扩展受限 较高:切换产品仅需替换具体工厂子类,支持动态扩展和切换
适用场景 产品数量少、变动少,追求简洁性(如3-5个同类产品) 产品数量多、可能持续扩展,追求扩展性(如超过5个同类产品)
维护成本 低:类数量少,逻辑集中,适合小型场景 中:类数量多,但职责清晰,扩展时维护成本低,适合中大型场景
初始化逻辑 所有产品的初始化逻辑集中在一个工厂,易冗余 每个产品的初始化逻辑封装在对应工厂,职责内聚,清晰易维护