PHP 简单工厂模式

概述

简单工厂模式(Simple Factory Pattern)是 PHP 中最基础、最常用的创建型设计模式之一,也被称为“静态工厂模式”。

其核心目标是将对象的创建逻辑与使用逻辑分离,通过一个统一的“工厂类”负责实例化不同类型的产品对象,客户端无需关心对象的创建细节(如类名、构造参数、依赖关系),仅需通过工厂类的静态方法传入指定参数,即可获取所需实例。

核心价值

  • 降低耦合:客户端与具体产品类解耦,修改产品类名或构造逻辑时,仅需修改工厂类,无需改动所有调用处;
  • 简化创建:隐藏对象创建的复杂逻辑(如参数校验、依赖初始化),客户端通过简单参数即可获取实例;
  • 统一管理:集中管理同类产品的创建逻辑,便于后续扩展、维护和迭代(如新增产品时仅需扩展工厂类)。

适用场景

  • 产品类数量较少且逻辑相对简单(如 3-5 个同类产品);
  • 客户端无需关心对象创建细节,仅需根据参数获取对应实例;
  • 产品类具有共同的父类或实现统一接口(保证工厂返回实例的一致性)。

注意事项

  • 不符合“开闭原则”:新增产品时需修改工厂类的判断逻辑(如添加 case 分支),适用于产品变动不频繁的场景;
  • 避免过度设计:若产品类过多(如 10 个以上)或创建逻辑复杂,建议升级为“工厂方法模式”或“抽象工厂模式”。

完整代码

<?php
declare(strict_types = 1);

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

/**
 * 具体产品A:实现产品接口
 * Class ProductA
 */
class ProductA implements ProductInterface
{
    public function doService(): string
    {
        return "产品A:执行服务逻辑(如支付宝支付处理)";
    }
}

/**
 * 具体产品B:实现产品接口
 * Class ProductB
 */
class ProductB implements ProductInterface
{
    public function doService(): string
    {
        return "产品B:执行服务逻辑(如微信支付处理)";
    }
}

/**
 * 具体产品C:实现产品接口
 * Class ProductC
 */
class ProductC implements ProductInterface
{
    public function doService(): string
    {
        return "产品C:执行服务逻辑(如银行卡支付处理)";
    }
}

/**
 * 简单工厂类:统一创建所有产品实例
 * Class SimpleFactory
 */
class SimpleFactory
{
    /**
     * 获取产品实例(静态方法,无需实例化工厂)
     * @param string $productType 产品类型标识(如 'a'/'b'/'c')
     * @return ProductInterface 产品实例(遵循统一接口)
     * @throws \InvalidArgumentException 当产品类型不支持时抛出异常
     */
    public static function createProduct(string $productType): ProductInterface
    {
        // 参数校验:避免无效输入
        $validTypes = ['a', 'b', 'c'];
        if (!in_array(strtolower($productType), $validTypes, true)) {
            throw new \InvalidArgumentException(
                sprintf("不支持的产品类型:%s,仅支持:%s", $productType, implode(',', $validTypes))
            );
        }

        // 根据产品类型创建对应实例
        return match (strtolower($productType)) {
            'a' => new ProductA(),
            'b' => new ProductB(),
            'c' => new ProductC(),
        };
    }
}

// 测试代码
try {
    // 1. 获取产品A实例并调用服务
    $productA = SimpleFactory::createProduct('a');
    echo $productA->doService() . PHP_EOL; // 输出:产品A:执行服务逻辑(如支付宝支付处理)

    // 2. 获取产品B实例并调用服务
    $productB = SimpleFactory::createProduct('B'); // 支持大小写不敏感
    echo $productB->doService() . PHP_EOL; // 输出:产品B:执行服务逻辑(如微信支付处理)

    // 3. 获取产品C实例并调用服务
    $productC = SimpleFactory::createProduct('c');
    echo $productC->doService() . PHP_EOL; // 输出:产品C:执行服务逻辑(如银行卡支付处理)

    // 4. 测试无效产品类型(会抛出异常)
    // $invalidProduct = SimpleFactory::createProduct('d');
} catch (\InvalidArgumentException $e) {
    echo "错误:" . $e->getMessage();
}

核心设计说明

1. 核心结构拆解

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

// 2. 具体产品类:实现产品接口,封装自身业务逻辑
class ProductA implements ProductInterface
{
    public function doService(): string { /* 业务逻辑 */ }
}

// 3. 工厂类:静态方法接收参数,创建并返回对应产品实例
class SimpleFactory
{
    public static function createProduct(string $productType): ProductInterface
    {
        // 参数校验 + 实例化逻辑
    }
}

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

// 优化1:引入产品接口,强制所有产品遵循统一规范,提升代码一致性
interface ProductInterface { /* 统一方法定义 */ }

// 优化2:添加参数校验,避免无效输入导致的逻辑错误
$validTypes = ['a', 'b', 'c'];
if (!in_array(strtolower($productType), $validTypes, true)) {
    throw new \InvalidArgumentException("不支持的产品类型");
}

// 优化3:使用 match 表达式(PHP 8.0+)替代 switch,代码更简洁高效
return match (strtolower($productType)) {
    'a' => new ProductA(),
    'b' => new ProductB(),
    'c' => new ProductC(),
};

// 优化4:支持产品类型大小写不敏感,提升使用灵活性
strtolower($productType);

// 优化5:明确返回类型声明(ProductInterface),增强代码可读性和类型安全性
public static function createProduct(string $productType): ProductInterface

3. 常见错误规避

// 错误1:未定义产品接口,产品类无统一规范,后续扩展易混乱
// 解决:强制所有产品实现 ProductInterface

// 错误2:缺少参数校验,传入无效类型时返回 null 或报错不明确
// 解决:添加 in_array 校验,抛出具体的 InvalidArgumentException

// 错误3:使用硬编码类名,修改产品类名时需多处改动
// 解决:集中在工厂类管理,修改仅需改工厂类的 match 分支

// 错误4:工厂方法非静态,需实例化工厂才能使用,冗余繁琐
// 解决:工厂方法设为 static,直接通过类名调用(SimpleFactory::createProduct())

补充说明

  1. PHP 版本适配

    • 代码中 match 表达式需 PHP 8.0 及以上版本;

    • 如果使用 PHP 8.0 以下版本,可替换为 switch 语句:

      switch (strtolower($productType)) {
       case 'a':
           return new ProductA();
       case 'b':
           return new ProductB();
       case 'c':
           return new ProductC();
       default:
           throw new \InvalidArgumentException("不支持的产品类型");
      }
  2. 扩展场景示例

    如果需要新增产品 D,仅需两步操作(虽然修改工厂类,但简单高效):

    // 1. 新增产品类并实现接口
    class ProductD implements ProductInterface
    {
       public function doService(): string
       {
           return "产品D:执行服务逻辑(如ApplePay支付处理)";
       }
    }
    
    // 2. 工厂类中添加对应分支
    return match (strtolower($productType)) {
       'a' => new ProductA(),
       'b' => new ProductB(),
       'c' => new ProductC(),
       'd' => new ProductD(), // 新增分支
       default: throw new \InvalidArgumentException(...);
    };
  3. 实际应用场景

    • 支付方式选择(支付宝/微信/银行卡/ApplePay);

    • 日志驱动切换(文件日志/数据库日志/Redis日志);

    • 缓存适配器创建(本地缓存/Redis缓存/Memcached缓存)。