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)
什么时候用
需要根据不同条件创建不同对象的时候,比如:
- 根据支付类型创建不同的支付对象(微信、支付宝、银行卡)
- 根据数据库类型创建不同的数据库对象(MySQL、Redis)
简单工厂
<?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);
工厂模式的好处
- 解耦:客户端不需要知道具体怎么创建对象
- 易扩展:新增支付方式只需要加一个类和工厂里的一个 case
- 统一管理:所有对象的创建都在工厂里,方便维护
三、观察者模式(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'
]);
观察者模式的好处
- 解耦:事件主体不需要知道谁在监听
- 易扩展:新增监听者只需要加一个类,不需要改原来的代码
- 符合开闭原则:对扩展开放,对修改关闭
四、什么时候用什么模式
| 场景 | 用什么模式 |
|---|---|
| 全局只需要一个实例 | 单例 |
| 根据条件创建不同对象 | 工厂 |
| 一个动作触发多个后续操作 | 观察者 |
五、常见坑
- 单例用太多:单例用多了会变成全局变量,代码难维护
- 工厂过度设计:简单逻辑就别硬上工厂,会增加复杂度
- 观察者滥用:所有操作都做成观察者,调试会很痛苦
总结
设计模式是工具,不是目的。
- 单例:保证全局只有一个实例
- 工厂:统一管理对象创建
- 观察者:一个事件,多个响应
用对了让代码更清晰,用错了让代码更复杂。记住:先解决问题,再考虑模式。