观察者模式是否为冗余层?求其作用、适用场景及实例说明
观察者模式:为什么它不是冗余层级?
嘿,我完全懂你现在的感受——刚接触观察者模式的时候,我也心里犯嘀咕:“这不就是多套了一层吗?直接调用方法不也能搞定?”但真等碰到复杂场景,就会发现这层“冗余”其实是解耦和扩展性的核心保障。咱们结合PHP实例来掰扯清楚~
先看不用观察者模式的“朴素写法”
假设你要做一个新闻发布系统,发布新闻时要给用户发邮件和短信通知。不用观察者的话,代码大概是这样:
class NewsPublisher { public function publishNews($news) { echo "发布新闻:{$news}\n"; // 硬编码调用邮件通知 $emailNotifier = new EmailNotifier(); $emailNotifier->send($news); // 硬编码调用短信通知 $smsNotifier = new SmsNotifier(); $smsNotifier->send($news); // 以后要加推送通知?得改这里的代码! } } class EmailNotifier { public function send($news) { echo "发送邮件通知:{$news}\n"; } } class SmsNotifier { public function send($news) { echo "发送短信通知:{$news}\n"; } }
这里的问题很明显:每次新增/移除通知方式,都得修改NewsPublisher的代码,违反了“对扩展开放、对修改关闭”的开闭原则。而且NewsPublisher和具体的通知类耦合死了,完全没法复用。
用观察者模式重构后的代码
这就是观察者模式发挥作用的时候了,咱们来实现标准的PHP版本:
// 观察者接口:定义所有观察者必须实现的方法 interface Observer { public function update($news); } // 主题接口:定义主题的核心行为(添加/移除观察者、通知) interface Subject { public function attach(Observer $observer); public function detach(Observer $observer); public function notify($news); } // 具体主题:新闻发布器 class NewsPublisher implements Subject { private $observers = []; // 添加观察者 public function attach(Observer $observer) { $this->observers[] = $observer; } // 移除观察者 public function detach(Observer $observer) { $key = array_search($observer, $this->observers); if ($key !== false) { unset($this->observers[$key]); } } // 通知所有观察者 public function notify($news) { foreach ($this->observers as $observer) { $observer->update($news); } } // 发布新闻的核心逻辑 public function publishNews($news) { echo "发布新闻:{$news}\n"; // 只需要通知,不用管谁来接收 $this->notify($news); } } // 具体观察者:邮件通知 class EmailNotifier implements Observer { public function update($news) { echo "发送邮件通知:{$news}\n"; } } // 具体观察者:短信通知 class SmsNotifier implements Observer { public function update($news) { echo "发送短信通知:{$news}\n"; } } // 使用示例 $publisher = new NewsPublisher(); $emailNotifier = new EmailNotifier(); $smsNotifier = new SmsNotifier(); // 注册观察者 $publisher->attach($emailNotifier); $publisher->attach($smsNotifier); $publisher->publishNews("PHP 8.3 正式发布!"); // 后来要加推送通知?不用改NewsPublisher!直接加个观察者类就行 class PushNotifier implements Observer { public function update($news) { echo "发送推送通知:{$news}\n"; } } $pushNotifier = new PushNotifier(); $publisher->attach($pushNotifier); $publisher->publishNews("Stack Overflow 推出新功能!");
观察者模式的核心作用与重要性
- 彻底解耦依赖:主题(
NewsPublisher)完全不知道具体有哪些观察者,只需要知道它们实现了Observer接口;观察者也不用关心主题的内部逻辑,只需要接收通知。两者的耦合度降到了最低。 - 极致的扩展性:新增任何类型的通知(比如微信通知、APP推送),只需要新增一个实现
Observer的类,然后注册到主题即可,完全不用修改主题代码。 - 动态管理观察者:可以随时添加或移除观察者,比如某个用户不想接收短信通知,只需要调用
detach方法移除对应的观察者,灵活度拉满。 - 代码结构更清晰:把“触发事件”和“处理事件”的逻辑分开,主题专注于核心业务(发布新闻),观察者专注于各自的业务(发邮件、发短信),代码职责更单一。
什么时候该用观察者模式?
如果你碰到以下场景,别犹豫,直接上观察者模式:
- 事件驱动场景:比如GUI按钮点击后多个组件响应、后端接口调用成功后触发一系列后续操作(比如订单支付成功后扣库存、加积分、发通知)。
- 一对多状态同步:比如股票价格更新后,K线图、价格标签、通知栏等多个组件需要同步显示最新价格。
- 订阅-发布场景:比如博客更新后通知订阅用户、公众号推文推送粉丝、消息队列的消费逻辑(本质就是分布式的观察者模式)。
- 日志/监控系统:一个操作需要同时记录到文件日志、数据库日志、远程监控平台。
最后说回你的疑问
你觉得它是冗余层级,大概率是因为你目前的场景比较简单(比如只有一个观察者),这时候直接调用确实能完成任务。但设计模式是为了解决未来的复杂问题——当你的系统需求变多、依赖关系变复杂时,这层“冗余”就会变成你维护代码的救命稻草。
内容的提问来源于stack exchange,提问作者user9115388
相关产品推荐
相关产品推荐

