PHP 怎么工厂模式

wen PHP项目 2


《PHP工厂模式深度解剖:从新手到架构师的进阶之路(附实战代码)》**

PHP 怎么工厂模式


目录导读

  1. 为什么你需要工厂模式?——从一段“糟糕”的代码说起
  2. 工厂模式家族图谱:简单工厂、工厂方法、抽象工厂
  3. 核心实战:用PHP实现三种工厂模式(附完整可运行代码)
  4. 工厂模式在Laravel框架中的真实应用(服务容器与门面)
  5. 高频面试题问答:工厂模式 vs 单例模式 vs 依赖注入
  6. 何时不该用工厂模式?——设计过度陷阱警示
  7. 工厂模式的“道”与“术”

为什么你需要工厂模式?——从一段“糟糕”的代码说起

假设你在开发一个电商系统,需要处理多种支付方式(支付宝、微信、PayPal),初级程序员可能会这样写:

// 订单处理逻辑
if ($payType == 'alipay') {
    $pay = new Alipay();
} elseif ($payType == 'wechat') {
    $pay = new WechatPay();
} elseif ($payType == 'paypal') {
    $pay = new Paypal();
}
$pay->pay($amount);

这段代码的致命缺陷:

  • 违背开闭原则:每增加一种支付方式,必须修改这段业务代码。
  • 耦合度高:业务层直接依赖具体支付类,无法独立测试。
  • 重复劳动:如果支付类还有参数配置(如密钥),每次实例化都要重复初始化。

工厂模式的核心思想:将对象的创建逻辑封装到一个独立的类(工厂)中,业务代码只依赖工厂接口,从而将“使用对象”与“创建对象”彻底解耦。


工厂模式家族图谱:简单工厂、工厂方法、抽象工厂

工厂模式并非单一模式,而是一个家族,三者关系层层递进:

模式类型 核心特点 适用场景 典型代码结构
简单工厂 一个工厂类,根据参数返回不同产品 产品种类少,且产品类无等级结构 PaymentFactory::create($type)
工厂方法 每个产品对应一个具体工厂,通过继承工厂接口实现 需要推迟产品创建到子类 abstract class PaymentFactory { abstract create(); }
抽象工厂 创建一系列相关或相互依赖的产品族 产品族概念明确(如“小米生态链产品”) abstract class DeviceFactory { createPhone(); createWatch(); }

关键区别

  • 简单工厂是“一夫多妻制”——上帝工厂决定一切。
  • 工厂方法是“多子多福”——每个工厂只生一个孩子。
  • 抽象工厂是“家族联姻”——一个工厂必须生出一整套产品。

核心实战:用PHP实现三种工厂模式(附完整可运行代码)

场景:物流系统需要发货,支持不同的快递公司(顺丰、圆通、中通)。

① 简单工厂(Simple Factory)

interface Shipping {
    public function send($package);
}
class SFExpress implements Shipping {
    public function send($package) {
        echo "顺丰已揽收:{$package}\n";
    }
}
class YTOExpress implements Shipping {
    public function send($package) {
        echo "圆通已揽收:{$package}\n";
    }
}
class ShippingFactory {
    public static function create($company) {
        switch ($company) {
            case 'sf': return new SFExpress();
            case 'yt': return new YTOExpress();
            default: throw new Exception("未知快递公司");
        }
    }
}
// 客户端使用
$shipping = ShippingFactory::create('sf');
$shipping->send('包裹#001');

② 工厂方法(Factory Method)

abstract class ShippingFactory {
    abstract public function createShipping(): Shipping;
    public function ship($package) {
        $shipping = $this->createShipping();
        $shipping->send($package);
    }
}
class SFFactory extends ShippingFactory {
    public function createShipping(): Shipping {
        return new SFExpress();
    }
}
class YTOFactory extends ShippingFactory {
    public function createShipping(): Shipping {
        return new YTOExpress();
    }
}
// 客户端
$factory = new SFFactory();
$factory->ship('包裹#002');

③ 抽象工厂(Abstract Factory)

interface 智能硬件Factory {
    public function createPhone(): Phone;
    public function createRouter(): Router;
}
class XiaomiFactory implements 智能硬件Factory {
    public function createPhone(): Phone {
        return new MiPhone();
    }
    public function createRouter(): Router {
        return new MiRouter();
    }
}
class HuaweiFactory implements 智能硬件Factory {
    public function createPhone(): Phone {
        return new HuaweiPhone();
    }
    public function createRouter(): Router {
        return new HuaweiRouter();
    }
}
// 客户端可通过工厂一次性获得全套产品

工厂模式在Laravel框架中的真实应用(服务容器与门面)

PHP最热门的Laravel框架处处渗透着工厂模式:

  • 服务容器解析app(Alipay::class) 本质是通过反射调用工厂方法进行自动依赖注入。
  • 门面(Facade)Cache::get() 的底层是 CacheManager 工厂,根据配置动态创建 RedisConnectorDatabaseConnector
  • 队列驱动Queue::connection('sqs') 内部通过工厂选择SQS或Redis驱动。

真实生产代码
Laravel中的 DatabaseManager 就是一个标准工厂——根据配置动态生成 MySQL、PostgreSQL 或 SQLite 连接实例,且支持连接池复用。


高频面试题问答:工厂模式 vs 单例模式 vs 依赖注入

Q1:工厂模式和单例模式能否结合?
可以,例如Laravel的容器就是“单例工厂”——它创建的对象默认是单例(共享),但也可以通过 bind 方法强制每次生产新实例。

Q2:工厂模式和依赖注入(DI)有什么区别?

  • 工厂模式是“你让我建,我建好给谁”。
  • 依赖注入是“你不必建,外面有人给你送”。
    两者常配合:容器(DI容器)内部通常使用工厂模式来创建实例。

Q3:抽象工厂和工厂方法都返回产品,怎么选?
如果产品之间存在强关联性(小米手机必须配小米路由”),使用抽象工厂;如果产品是独立个体,选择工厂方法,判断标准:产品族 vs 产品层级


何时不该用工厂模式?——设计过度陷阱警示

工厂模式并非万能银弹,以下情况应果断放弃:

  • 产品只有两个,且几乎不变:直接 new 反而清晰。
  • 实例化过程极度简单(如 new stdClass),工厂只会增加一个无用层级。
  • 框架已内置容器:在Laravel中,直接通过容器调用 app() 即可,无需手写工厂类。
  • 测试驱动场景:如果单纯为了mock,优先使用依赖注入,而不是工厂模式。

行业实证:GitHub 上大量 PHP 老旧代码,过度工厂化导致调试困难,知名 PHPStorm 插件 PHP Mess Detector 甚至会检测“滥用工厂”给出警告。


工厂模式的“道”与“术”

“术”层面
掌握三种工厂的UML类图与分工明确,区分“想要一个产品”还是“想要一整套产品”。

“道”层面
工厂模式的本质是封装变化——把“将来可能扩展的创建逻辑”集中管理,它让软件系统更有弹性,让每一次业务扩展只是新增一个类,而不必修改旧代码(满足开闭原则)。

最后一句忠告:真实项目中,80%的工厂模式使用“简单工厂”就够用;只有系统规模大到产品族爆炸时,才建议上抽象工厂,设计模式是解决问题的工具,不是用来炫耀的证书。


(全文完)

抱歉,评论功能暂时关闭!