«

PHP 设计模式:单例、工厂、观察者实战详解

时间:2026-10-4 10:08     作者:emer     分类: 无


前言

设计模式不是八股文,它是前人踩坑踩出来的最佳实践。PHP 开发中最常用的三个设计模式:单例、工厂、观察者。本文用最直白的方式讲清楚。

一、单例模式(Singleton)

什么时候用

全局只需要一个实例的对象,比如:

代码实现

<?php
class Database
{
    private static $instance = null;
    private $conn;

    // 构造函数私有化,防止外部 new
    private function __construct()
    {
        $this->conn = mysqli_connect('localhost', 'user', 'pass', 'db');
    }

    // 禁止克隆
    private function __clone() {}

    // 禁止反序列化
    public function __wakeup()
    {
        throw new Exception("不能反序列化单例");
    }

    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function getConnection()
    {
        return $this->conn;
    }
}

// 使用
$db = Database::getInstance();
$conn = $db->getConnection();

为什么要私有化构造函数

如果构造函数是 public 的,外面就能 new Database(),那就不是单例了。

二、工厂模式(Factory)

什么时候用

需要根据不同条件创建不同对象的时候,比如:

简单工厂

<?php
interface Payment
{
    public function pay($amount);
}

class WechatPay implements Payment
{
    public function pay($amount)
    {
        echo "微信支付 {$amount} 元";
    }
}

class Alipay implements Payment
{
    public function pay($amount)
    {
        echo "支付宝支付 {$amount} 元";
    }
}

class PaymentFactory
{
    public static function make($type)
    {
        switch ($type) {
            case 'wechat':
                return new WechatPay();
            case 'alipay':
                return new Alipay();
            default:
                throw new Exception("不支持的支付方式");
        }
    }
}

// 使用
$pay = PaymentFactory::make('wechat');
$pay->pay(100);

工厂模式的好处

  1. 解耦:客户端不需要知道具体怎么创建对象
  2. 易扩展:新增支付方式只需要加一个类和工厂里的一个 case
  3. 统一管理:所有对象的创建都在工厂里,方便维护

三、观察者模式(Observer)

什么时候用

一个对象状态改变时,需要通知多个其他对象,比如:

代码实现

<?php
// 事件接口
interface Observer
{
    public function update($eventData);
}

// 事件主体
class Event
{
    private $observers = [];

    public function attach(Observer $observer)
    {
        $this->observers[] = $observer;
    }

    public function trigger($eventData)
    {
        foreach ($this->observers as $observer) {
            $observer->update($eventData);
        }
    }
}

// 具体观察者
class SendEmail implements Observer
{
    public function update($eventData)
    {
        echo "发送邮件给 {$eventData['email']}\n";
    }
}

class SendSms implements Observer
{
    public function update($eventData)
    {
        echo "发送短信给 {$eventData['phone']}\n";
    }
}

class GivePoints implements Observer
{
    public function update($eventData)
    {
        echo "给用户送 100 积分\n";
    }
}

// 使用
$event = new Event();
$event->attach(new SendEmail());
$event->attach(new SendSms());
$event->attach(new GivePoints());

// 用户注册,触发事件
$event->trigger([
    'email' => 'user@example.com',
    'phone' => '13800138000'
]);

观察者模式的好处

  1. 解耦:事件主体不需要知道谁在监听
  2. 易扩展:新增监听者只需要加一个类,不需要改原来的代码
  3. 符合开闭原则:对扩展开放,对修改关闭

四、什么时候用什么模式

场景 用什么模式
全局只需要一个实例 单例
根据条件创建不同对象 工厂
一个动作触发多个后续操作 观察者

五、常见坑

  1. 单例用太多:单例用多了会变成全局变量,代码难维护
  2. 工厂过度设计:简单逻辑就别硬上工厂,会增加复杂度
  3. 观察者滥用:所有操作都做成观察者,调试会很痛苦

总结

设计模式是工具,不是目的。

用对了让代码更清晰,用错了让代码更复杂。记住:先解决问题,再考虑模式。

标签: PHP 设计模式 单例 工厂模式 观察者模式