简短描述
在观察者模式中,有一个主题和几个观察者,主题状态改变之后会通知到所有的观察者。
现实中的观察者模式
观察者模式和现实世界很好对应。比如我和我的朋友们购买了今年一年的报纸,每次报社印刷了今天的报纸之后就会往我这里送。在这个系统里面,“报社“是一个主题,“我和我的朋友们”就是一个观察者,当“报社”生产报纸之后,“我和我的朋友们”都能收到这份报纸。
根据上面的描述,我们很容易写出一个观察者模式。首先定义一个报社作为主题,然后定义一些用户作为观察者。不过在此之前,我们先定义主题和观察者的接口,毕竟我们是面向接口编程。
定义一个主题接口
namespace ds\observer\contract; /** * 主题接口 */ interface Subject { /** * 添加一个观察者 * @param Observer $observer */ public function add(Observer $observer); /** * 移除一个观察者 * @param Observer $observer * @return boolean */ public function remove(Observer $observer); /** * 通知所有观察者 * @param mixed $data * @return boolean */ public function notify($data); }
定义一个观察者接口
namespace ds\observer\contract; /** * 观察者 */ interface Observer { /** * 执行自己的逻辑 * @param mixed $data * @return boolean */ public function execute($data); }
定义报社,实现主题接口
namespace ds\observer; /** * 报社主题 */ class Newspaper implements contract\Subject { protected $Observers; /** * 添加一个观察者 * @param Observer $observer */ public function add(contract\Observer $observer) { $hash = $this->hash($observer); $this->Observers[$hash] = $observer; } /** * 移除一个观察者 * @param Observer $observer */ public function remove(contract\Observer $observer) { $hash = $this->hash($observer); unset($this->Observers[$hash]); } /** * 通知所有观察者 * @param mixed $data * @return boolean */ public function notify($data) { foreach ($this->Observers as $observer) { $observer->execute($data); } } protected function hash($obj) { return spl_object_hash($obj); } }
定义用户,实现观察者接口
namespace ds\observer; /** * 用户 */ class User implements contract\Observer { public function __construct($name) { $this->name = $name; } /** * 执行观察者自身逻辑 * @param string $data * @return void */ public function execute($data) { echo $this->name . "收到了" . $data . "\n"; } public function attach(contract\Subject $subject) { $subject->add($this); } }
执行主流程
到目前位置,我们创建了主题-报社、观察者-用户,他们分别实现了相应的接口,看起来一切准备就绪了。接着这些代码就可以跑起来了。
namespace ds\observer; require __DIR__ . '/contract/Observer.php'; require __DIR__ . '/contract/Subject.php'; require __DIR__ . '/Newspaper.php'; require __DIR__ . '/User.php'; // 创建一个新的报社 $newspaper = new Newspaper(); // 创建一个新的用户cmhc $cmhc = new User('cmhc'); // 让这个用户去订阅这个报纸 $cmhc->attach($newspaper); // 再创建一个用户xiaoming $xiaoming = new User('xiaoming'); // 让xiaoming也订阅这个报社 $xiaoming->attach($newspaper); // 报社今天发布了一个观察者模式,通知一下订阅我的人 $newspaper->notify('《设计模式之观察者模式》');
如果执行上面的代码,你会得到如下结果:
cmhc收到了《设计模式之观察者模式》 xiaoming收到了《设计模式之观察者模式》
可能很多人都知道观察者模式,也知道观察者模式要怎么去实现,但是却找不到具体的业务场景去使用它。但实际上观察者模式的应用是十分广泛的。下面就介绍几个经常使用观察者模式的几个场景
支付场景
在支付场景下,用户购买一件商品,当支付成功之后三方会回调自身,在这个时候系统可能会有很多需要执行的逻辑(如:更新订单状态,发送邮件通知,赠送礼品…),这些逻辑之间并没有强耦合,因此天然适合使用观察者模式去实现这些功能,当有更多的操作时,只需要添加新的观察者就能实现,完美实现了对修改关闭,对扩展开放的开闭原则。
UGC场景
在一个UGC场景下,用户发布的内容往往会经过很多流程,大部分是先发往审核系统,当审核通过之后就会出现一系列的业务逻辑,比如更新内容状态,通知给所有的粉丝等等。
你可能还喜欢下面这些文章
赞赏微信赞赏
支付宝赞赏
说得好清楚!一下子就看懂了!