Laravel的Event事件系统提供了一个简单的观察者模式实现,可以订阅和监听应用中发生的各类事件,在PHP的标准库(SPL)里甚至提供了三个接口SplSubject
, SplObserver
, SplObjectStorage
来让开发者更容易地实现观察者模式,不过我仍是想脱离SPL提供的接口和特定编程语言来讲一下如何经过面向对象程序设计来实现观察者模式,示例是PHP代码不过用其余面向对象语言实现起来也是同样的。git
观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆获得通知并被自动更新。观察者模式又叫作发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。github
观察者模式的核心在于Subject和Observer接口,Subject(主题目标)包含一个给定的状态,观察者“订阅”这个主题,将主题的当前状态通知观察者,每次给定状态改变时全部观察者都会获得通知。编程
发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标能够对应多个观察者,并且这些观察者之间没有相互联系,能够根据须要增长和删除观察者,使得系统更易于扩展。bash
好比在设置用户(主题)的状态后要分别发送当前的状态描述信息给用户的邮箱和手机,咱们能够使用两个观察者订阅用户的状态,一旦设置状态后主题就会通知的订阅了状态改变的观察者,在两个观察者里面咱们能够分别来实现发送邮件信息和短信信息的功能。编程语言
abstract class Subject
{
protected $stateNow;
protected $observers = [];
public function attach(Observer $observer)
{
array_push($this->observers, $observer);
}
public function detach(Observer $ob)
{
$pos = 0;
foreach ($this->observers as $viewer) {
if ($viewer == $ob) {
array_splice($this->observers, $pos, 1);
}
$pos++;
}
}
public function notify()
{
foreach ($this->observers as $viewer) {
$viewer->update($this);
}
}
}
复制代码
在抽象类中attach
detach
和notify
都是具体方法,这些是继承才能使用的方法,将由Subject
的子类使用。学习
class ConcreteSubject extends Subject
{
public function setState($state)
{
$this->stateNow = $state;
$this->notify();
}
public function getState()
{
return $this->stateNow;
}
}
复制代码
abstract class Observer
{
abstract public function update(Subject $subject);
}
复制代码
在抽象观察者中,抽象方法update
等待子类为它提供一个特定的实现。ui
class ConcreteObserverDT extends Observer
{
private $currentState;
public function update(Subject $subject)
{
$this->currentState = $subject->getState();
echo '<div style="font-size:10px;">'. $this->currentState .'</div>';
}
}
class ConcreteObserverPhone extends Observer
{
private $currentState;
public function update(Subject $subject)
{
$this->currentState = $subject->getState();
echo '<div style="font-size:20px;">'. $this->currentState .'</div>';
}
}
复制代码
在例子中为了理解起来简单,咱们只是根据不一样的客户端设置了不一样的内容样式,实际应用中能够真正的调用邮件和短信服务来发送信息。this
class Client
{
public function __construct()
{
$sub = new ConcreteSubject();
$obDT = new ConcreteObserverDT();
$obPhone = new ConcreteObserverPhone();
$sub->attach($obDT);
$sub->attach($obPhone);
$sub->setState('Hello World');
}
}
$worker = new Client();
复制代码
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知全部观察者对象,使它们可以自动更新。spa
模式包含四个角色:目标又称为主题,它是指被观察的对象;具体目标是目标类的子类,一般它包含有常常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;观察者将对观察目标的改变作出反应;在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态须要和具体目标的状态保持一致。设计
观察者模式的主要优势在于能够实现表示层和数据逻辑层的分离,并在观察目标和观察者之间创建一个抽象的耦合,支持广播通讯;其主要缺点在于若是一个观察目标对象有不少直接和间接的观察者的话,将全部的观察者都通知到会花费不少时间,并且若是在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能致使系统崩溃。
本文已经收录在系列文章Laravel核心代码学习里,欢迎访问阅读。