当前位置: 首页 > news >正文

PHP设计模式观察者与中介者实现

PHP设计模式观察者与中介者实现

观察者模式和中介者模式都是用于对象间通信的设计模式。观察者模式实现一对多的依赖关系,中介者模式减少多对多的直接通信。今天用实际代码说明这两种模式。

观察者模式的核心是当一个对象状态变化时,所有依赖它的对象都得到通知。PHP的SPL提供了SplSubject和SplObserver接口。

```php
// 订单状态变更的事件系统
class Order implements SplSubject
{
private SplObjectStorage $observers;
private array $data;

public function __construct(array $data)
{
$this->data = $data;
$this->observers = new SplObjectStorage();
}

public function attach(SplObserver $observer): void
{
$this->observers->attach($observer);
}

public function detach(SplObserver $observer): void
{
$this->observers->detach($observer);
}

public function notify(): void
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}

public function setStatus(string $status): void
{
$oldStatus = $this->data['status'] ?? 'unknown';
$this->data['status'] = $status;
echo "订单 {$this->data['id']} 状态变更: $oldStatus -> $status\n";
$this->notify();
}

public function getData(): array
{
return $this->data;
}
}

class EmailNotifier implements SplObserver
{
public function update(SplSubject $subject): void
{
if (!$subject instanceof Order) return;
$data = $subject->getData();

$messages = [
'paid' => "订单 {$data['id']} 已支付,发送确认邮件",
'shipped' => "订单 {$data['id']} 已发货,发送物流通知",
'cancelled' => "订单 {$data['id']} 已取消,发送退款通知",
];

if (isset($messages[$data['status']])) {
echo " [邮件] {$messages[$data['status']]}\n";
}
}
}

class SmsNotifier implements SplObserver
{
public function update(SplSubject $subject): void
{
if (!$subject instanceof Order) return;
$data = $subject->getData();

if ($data['status'] === 'shipped') {
echo " [短信] 订单 {$data['id']} 已发货,通知用户\n";
}
}
}

class InventoryUpdater implements SplObserver
{
public function update(SplSubject $subject): void
{
if (!$subject instanceof Order) return;
$data = $subject->getData();

if ($data['status'] === 'paid') {
echo " [库存] 订单 {$data['id']} 扣减库存\n";
} elseif ($data['status'] === 'cancelled') {
echo " [库存] 订单 {$data['id']} 恢复库存\n";
}
}
}

class LoggerObserver implements SplObserver
{
public function update(SplSubject $subject): void
{
if (!$subject instanceof Order) return;
$data = $subject->getData();
echo " [日志] 订单 {$data['id']} 状态: {$data['status']}\n";
}
}

// 使用
$order = new Order(['id' => 'ORD-2024-0001', 'amount' => 299.00]);
$order->attach(new EmailNotifier());
$order->attach(new SmsNotifier());
$order->attach(new InventoryUpdater());
$order->attach(new LoggerObserver());

$order->setStatus('paid');
$order->setStatus('shipped');
?>
```

中介者模式减少对象之间的直接通信,通过中介者协调交互。聊天室是一个经典的例子。

```php
interface ChatMediator
{
public function sendMessage(User $sender, string $message): void;
public function sendPrivateMessage(User $sender, User $recipient, string $message): void;
public function addUser(User $user): void;
public function removeUser(User $user): void;
}

class ChatRoom implements ChatMediator
{
private array $users = [];
private array $messageHistory = [];

public function addUser(User $user): void
{
$this->users[$user->getName()] = $user;
$user->setMediator($this);

$this->broadcastSystemMessage("{$user->getName()} 加入了聊天室");
}

public function removeUser(User $user): void
{
unset($this->users[$user->getName()]);
$this->broadcastSystemMessage("{$user->getName()} 离开了聊天室");
}

public function sendMessage(User $sender, string $message): void
{
$this->messageHistory[] = [
'from' => $sender->getName(),
'message' => $message,
'time' => date('H:i:s'),
'type' => 'public',
];

foreach ($this->users as $name => $user) {
if ($user !== $sender) {
$user->receive($sender->getName(), $message);
}
}
}

public function sendPrivateMessage(User $sender, User $recipient, string $message): void
{
$this->messageHistory[] = [
'from' => $sender->getName(),
'to' => $recipient->getName(),
'message' => $message,
'time' => date('H:i:s'),
'type' => 'private',
];

$recipient->receivePrivate($sender->getName(), $message);
$sender->notify("私信已发送给 {$recipient->getName()}");
}

private function broadcastSystemMessage(string $message): void
{
foreach ($this->users as $user) {
$user->receiveSystem($message);
}
}

public function getMessageHistory(): array
{
return $this->messageHistory;
}
}

class User
{
private ?ChatMediator $mediator = null;

public function __construct(
private string $name
) {}

public function setMediator(ChatMediator $mediator): void
{
$this->mediator = $mediator;
}

public function getName(): string
{
return $this->name;
}

public function send(string $message): void
{
echo "{$this->name} 发送: $message\n";
$this->mediator->sendMessage($this, $message);
}

public function sendPrivate(User $recipient, string $message): void
{
echo "{$this->name} 私信 {$recipient->getName()}: $message\n";
$this->mediator->sendPrivateMessage($this, $recipient, $message);
}

public function receive(string $from, string $message): void
{
echo "[{$this->name}] {$from}: $message\n";
}

public function receivePrivate(string $from, string $message): void
{
echo "[{$this->name}] (私信) {$from}: $message\n";
}

public function receiveSystem(string $message): void
{
echo "[{$this->name}] (系统) $message\n";
}

public function notify(string $message): void
{
echo "[{$this->name}] $message\n";
}
}

$chatRoom = new ChatRoom();

$alice = new User('Alice');
$bob = new User('Bob');
$charlie = new User('Charlie');

$chatRoom->addUser($alice);
$chatRoom->addUser($bob);
$chatRoom->addUser($charlie);

echo "\n";
$alice->send('大家好!');
echo "\n";
$bob->send('Alice你好!');
echo "\n";
$charlie->sendPrivate($alice, '晚上一起吃饭吗?');
echo "\n";
$chatRoom->removeUser($charlie);
?>
```

中介者模式在UI组件之间协调时也很常用。比如表单中各个字段的联动。

```php
interface FormMediator
{
public function notify(FormComponent $sender, string $event, mixed $data = null): void;
}

class FormComponent
{
protected ?FormMediator $mediator = null;

public function __construct(protected string $name) {}

public function setMediator(FormMediator $mediator): void
{
$this->mediator = $mediator;
}

public function getName(): string
{
return $this->name;
}
}

class SelectField extends FormComponent
{
private string $value = '';
private array $options = [];

public function setOptions(array $options): void
{
$this->options = $options;
}

public function setValue(string $value): void
{
$this->value = $value;
echo "选择框 {$this->name} 选择: $value\n";
if ($this->mediator) {
$this->mediator->notify($this, 'change', $value);
}
}

public function getValue(): string
{
return $this->value;
}

public function getOptions(): array
{
return $this->options;
}
}

class InputField extends FormComponent
{
private string $value = '';
private bool $disabled = false;

public function setValue(string $value): void
{
$this->value = $value;
}

public function getValue(): string
{
return $this->value;
}

public function setDisabled(bool $disabled): void
{
$this->disabled = $disabled;
echo "输入框 {$this->name} " . ($disabled ? '禁用' : '启用') . "\n";
}
}

class SubmitButton extends FormComponent
{
private bool $enabled = false;

public function setEnabled(bool $enabled): void
{
$this->enabled = $enabled;
echo "提交按钮 " . ($enabled ? '可用' : '不可用') . "\n";
}

public function click(): void
{
if (!$this->enabled) {
echo "按钮不可用\n";
return;
}
echo "表单提交!\n";
if ($this->mediator) {
$this->mediator->notify($this, 'submit');
}
}
}

class UserFormMediator implements FormMediator
{
private SelectField $countrySelect;
private InputField $cityInput;
private InputField $phoneInput;
private SubmitButton $submitButton;

public function __construct()
{
$this->countrySelect = new SelectField('country');
$this->cityInput = new InputField('city');
$this->phoneInput = new InputField('phone');
$this->submitButton = new SubmitButton('submit');

$this->countrySelect->setMediator($this);
$this->cityInput->setMediator($this);
$this->phoneInput->setMediator($this);
$this->submitButton->setMediator($this);

$this->countrySelect->setOptions(['', '中国', '美国', '日本']);
$this->cityInput->setDisabled(true);
}

public function notify(FormComponent $sender, string $event, mixed $data = null): void
{
if ($sender === $this->countrySelect && $event === 'change') {
if (empty($data)) {
$this->cityInput->setDisabled(true);
$this->cityInput->setValue('');
$this->phoneInput->setDisabled(true);
$this->phoneInput->setValue('');
$this->submitButton->setEnabled(false);
} else {
$this->cityInput->setDisabled(false);
$this->phoneInput->setDisabled(false);
$this->submitButton->setEnabled(true);
}
}
}

public function getCountrySelect(): SelectField { return $this->countrySelect; }
public function getCityInput(): InputField { return $this->cityInput; }
public function getPhoneInput(): InputField { return $this->phoneInput; }
public function getSubmitButton(): SubmitButton { return $this->submitButton; }
}

$mediator = new UserFormMediator();
$mediator->getCountrySelect()->setValue('中国');
$mediator->getSubmitButton()->click();
?>
```

观察者模式适合一对多的通知场景,中介者模式适合多对多的协调场景。两种模式都能降低对象之间的耦合度,让系统更容易维护和扩展。

http://www.cnnetsun.cn/news/2745406.html

相关文章:

  • 如何利用Google 10000英语词频库提升NLP应用性能?
  • 别再纠结TB6600了!用拇指大的A4988驱动42步进电机,实测DIY升降台(附51/STM32/FPGA代码)
  • MySQL 8.0在Docker中大小写敏感配置终极指南:从原理到实战
  • 收藏!前端程序员必看:AI来了,我们真的会失业吗?附自救指南
  • 3个核心技巧:让Windows任务栏从实用工具变身视觉艺术
  • GPT-5.5级大模型:语义理解与意图推演的技术跃迁
  • 系统架构设计师下午题选题策略:五选三怎么选最容易
  • 008、STM32单片机分享:智能风扇系统
  • CANNBot SIMT API总览
  • 停止用AI写代码,开始用大脑建系统:从“提示词搬运工”到“架构决策者”的7天跃迁训练
  • 快手面试官问:Agent跑50轮突然变傻了
  • 崩坏星穹铁道自动化工具:三月七小助手完全指南
  • GTE-large-zh vs BGE-large-zh:全面对比与迁移学习方案终极指南
  • 天线阵列S2P批量解析与方向图参数一键计算(含高低频适配)
  • 别再只用-transparentcolor了!用Tkinter窗口叠加,轻松实现聊天框、悬浮球等UI的半透明效果
  • GPT-4 Turbo实战指南:128K上下文与跨模态理解如何重构AI落地
  • 如何快速掌握OpenCore Legacy Patcher:让旧Mac重获新生的完整指南
  • 告别SLAM跟踪丢失就卡住!用ORB-SLAM Atlas实现‘无缝续命’的保姆级原理拆解
  • AMCL定位突然失效?可能是你没处理好‘机器人绑架’和‘里程计漂移’
  • STM32F103C8T6驱动MAX30205测温:手把手教你搞定I2C多从机地址配置与数据读取
  • 终极指南:深入理解MOSS-Audio-Tokenizer-Nano-ONNX架构:编码器与流式解码器工作原理
  • 内部专家的“经验萃取”远比“人才引进”更重要
  • 编写程序,输入办公室空调温度,个人体感,分析温湿度对呼吸道,关节的影响并评级。
  • bonsai-image-ternary-4B-gemlite-2bit模型架构详解:MMDiT块与文本编码器设计
  • MakeMeAHanzi终极指南:免费开源汉字数据库,9000+汉字笔画动画全解析
  • 如何快速上手crt-animation-terminal-ltx-2.3-lora:5分钟创建复古CRT视频特效
  • 手把手教你用华为交换机DHCP地址池做网络健康度检查:看`used`、`idle`、`conflict`比例
  • 机器视觉:掩膜编辑
  • 从一次httpd部署故障讲起:手把手教你用patchelf和readelf诊断并修复Linux动态库依赖
  • Excel用户福音:用JimuReport积木报表的打印设计器,5分钟搞定不动产证、发票等复杂套打