观察者模式用于实现对对象进行观察:一旦主体对象状态发生改变,与之关联的观察者对象会收到通知,并进行相应操做。php
举个例子说明:
假设一个这样的情景,当公司有一个新员工入职了,入职的当天,HR须要为他办理入职手续,网管须要给他配好电脑和办公用品,部门主管须要带他熟悉部门。传统的编程方式,就是在员工入职这个事件发生的代码以后直接加入处理逻辑,当后续咱们须要增长处理逻辑时(好比员工入职后增长培训),代码会变得难以维护。这种方式是耦合的,侵入式的,增长新的逻辑须要改变事件主题的代码。运用观察者模式,将员工的入职做为事件,其余的处理逻辑都作为观察者的操做,那么,当之后须要再增长更多的逻辑时,新增逻辑代码就会很方便。具体代码实现以下。编程
首先定义一个观察者接口,全部的观察者都实现这个接口(为何要定义成接口呢?由于每个观察者的具体行为须要具体去实现,用接口定义一个统一的方法,具体的实现交给观察者去实现)工具
interface observer { public function update(); }
再定义一个事件生成器的抽象类,用来使继承它的事件都具备通知观察者的能力。this
abstract class EventGenerator { private $observers = []; //定义一个添加观察者的方法 public function addOberver(Observer $observer) { $this->observers[] = $observer; } //定义一个通知观察者的方法 public function notify() { foreach($this->observers as $observer) { $observer->update(); } } }
而后再来定义事件类.net
class event extends EventGenerator { //定义一个触发观察者的方法 public funtion trigger() { echo "Event <br/>"; //开始通知观察者 $this->notify(); } }
开始使用code
$event = new event(); $event->trigger();
这个时候,当咱们要在事件发生的时候增长别的操做,只须要新增观察者就能够了server
新增一个观察者对象
class Observer1 implements Observer { public function update() { echo "操做1<br/>"; } }
而后使用的时候就是继承
$event = new event(); // 增长观察者 $event->addObserver(new Observer1); $event->trigger();
若是须要在事件发生后再增长操做,只需再新增相应的观察者便可。接口
观察者模式解除了主体和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另外一边的变化。下降对象之间的耦合度以达到解耦的目的,符合"开闭原则"的要求。
PHP 经过内置的 SPL 扩展提供了对观察者模式的原生支持,其中的观察者由 3 个元素组成 : SplObserver 接口、 SplSubject 接口和 SplObjectStorage 工具类。下面是利用 SPL 实现观察者模式的代码。SPL 的地址见这里。
class MyObserver1 implements SplObserver { public function update(SplSubject $subject) { echo __CLASS__ . ' - ' . $subject->getName(); } } class MyObserver2 implements SplObserver { public function update(SplSubject $subject) { echo __CLASS__ . ' - ' . $subject->getName(); } } class MySubject implements SplSubject { private $observers; private $name; public function __construct($name) { $this->observers = new SplObjectStorage(); $this->name = $name; } public function attach(SplObserver $observer) { $this->observers->attach($observer); } public function detach(SplObserver $observer) { $this->observers->detach($observer); } public function notify() { foreach ($this->observers as $observer) { $observer->update($this); } } public function getName() { return $this->name; } } $observer1 = new MyObserver1(); $observer2 = new MyObserver2(); $subject = new MySubject("test"); $subject->attach($observer1); $subject->attach($observer2); $subject->notify(); /* 输出: MyObserver1 - test MyObserver2 - test */ $subject->detach($observer2); $subject->notify(); /* 输出: MyObserver1 - test */