[PHP]观察者模式实战
·
以下是一个 PHP 中观察者模式(Observer Pattern) 的具体应用示例,结合电商系统的场景,展示如何通过观察者模式实现对象间的松耦合通信。
🛒 一、场景:电商系统中的库存更新通知
假设我们有一个电商平台,当某个商品的库存发生变化时,需要通知以下系统模块:
- 客服系统:提醒客服库存不足;
- 邮件系统:向用户发送库存恢复通知;
- 短信系统:向用户发送库存恢复通知。
通过观察者模式,我们可以将这些模块解耦,使得商品库存的更新逻辑与通知逻辑分离。
🧱 二、代码实现(PHP)
1. 定义 Subject 接口和 Observer 接口
<?php
// 主题接口(被观察者)
interface Subject {
public function attach(Observer $observer): void; // 注册观察者
public function detach(Observer $observer): void; // 移除观察者
public function notify(): void; // 通知所有观察者
}
// 观察者接口
interface Observer {
public function update(Subject $subject): void; // 更新逻辑
}
2. 实现具体主题类(商品库存)
<?php
// 商品库存类(具体主题)
class Product implements Subject {
private array $observers = []; // 观察者列表
private int $stock = 0; // 当前库存
// 注册观察者
public function attach(Observer $observer): void {
$this->observers[] = $observer;
}
// 移除观察者
public function detach(Observer $observer): void {
$key = array_search($observer, $this->observers, true);
if ($key !== false) {
unset($this->observers[$key]);
}
}
// 通知所有观察者
public function notify(): void {
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
// 修改库存并触发通知
public function setStock(int $newStock): void {
$this->stock = $newStock;
$this->notify(); // 库存变化后通知观察者
}
// 获取当前库存
public function getStock(): int {
return $this->stock;
}
}
3. 实现具体观察者类
3.1客服系统观察者
<?php
class CustomerServiceObserver implements Observer {
public function update(Subject $subject): void {
if ($subject instanceof Product && $subject->getStock() < 10) {
echo "客服系统通知:商品库存不足(当前库存:" . $subject->getStock() . ")\n";
}
}
}
3.2 邮件系统观察者
<?php
class EmailObserver implements Observer {
public function update(Subject $subject): void {
if ($subject instanceof Product && $subject->getStock() > 0) {
echo "邮件系统通知:商品库存已恢复(当前库存:" . $subject->getStock() . ")\n";
}
}
}
3.3 短信系统观察者
<?php
class SMSObserver implements Observer {
public function update(Subject $subject): void {
if ($subject instanceof Product && $subject->getStock() > 0) {
echo "短信系统通知:商品库存已恢复(当前库存:" . $subject->getStock() . ")\n";
}
}
}
3.4. 客户端调用示例
<?php
// 创建商品对象
$product = new Product();
// 创建观察者对象
$customerService = new CustomerServiceObserver();
$emailService = new EmailObserver();
$smsService = new SMSObserver();
// 注册观察者
$product->attach($customerService);
$product->attach($emailService);
$product->attach($smsService);
// 模拟库存变化
echo "初始库存:5\n";
$product->setStock(5); // 触发客服系统的库存不足通知
echo "\n库存更新:15\n";
$product->setStock(15); // 触发邮件和短信系统的库存恢复通知
echo "\n库存更新:8\n";
$product->setStock(8); // 再次触发客服系统的库存不足通知
✅ 三、输出结果
初始库存:5
客服系统通知:商品库存不足(当前库存:5)
库存更新:15
邮件系统通知:商品库存已恢复(当前库存:15)
短信系统通知:商品库存已恢复(当前库存:15)
库存更新:8
客服系统通知:商品库存不足(当前库存:8)
🌟 四、优势与适用场景
4.1 优势
- 解耦:商品库存逻辑与通知逻辑完全分离,新增或移除观察者时无需修改主题类;
- 灵活性:可以动态注册/注销观察者,适应不同业务需求;
- 扩展性:新增观察者(如微信通知、App推送)只需添加新类,无需修改现有代码;
- 符合开闭原则:对扩展开放,对修改关闭。
4.2 适用场景
- 事件驱动系统:如用户注册后触发邮件、短信通知;
- 状态监控系统:如服务器监控、库存监控;
- GUI 界面更新:如数据变化后自动刷新视图;
- 消息队列:如异步任务触发多个消费者。
⚠️ 五、注意事项
- 性能问题:如果有大量观察者,频繁调用
notify()可能会影响性能; - 循环引用:避免观察者与主题之间的循环依赖,可能导致内存泄漏;
- 状态传递:观察者通过
update()方法获取主题状态时,需确保状态的准确性。
🧩 六、PHP 内置支持(SplSubject)
PHP 提供了内置的观察者接口 SplSubject 和 SplObserver,可以直接使用:
use SplSubject;
use SplObserver;
class Product implements SplSubject {
// 实现 attach(), detach(), notify() 方法
}
class EmailObserver implements SplObserver {
public function update(SplSubject $subject) {
// 处理逻辑
}
}
🧾 七、总结
观察者模式是一种经典的行为型设计模式,适用于一对多依赖关系的场景。通过将观察者与主题解耦,可以显著提升系统的灵活性和可维护性。在 PHP 项目中,观察者模式常用于事件驱动系统、消息通知系统等场景。
更多推荐


所有评论(0)