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();
?>
```
观察者模式适合一对多的通知场景,中介者模式适合多对多的协调场景。两种模式都能降低对象之间的耦合度,让系统更容易维护和扩展。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)