【一】模式定义
观察者模式有时也被称作发布/订阅模式,该模式用于为对象实现发布/订阅功能:一旦主体对象状态发生改变,与之关联的观察者对象会收到通知,并进行相应操作。
将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
消息队列系统、事件都使用了观察者模式。
PHP 为观察者模式定义了两个接口:SplSubject 和 SplObserver。SplSubject 可以看做主体对象的抽象,SplObserver 可以看做观察者对象的抽象,要实现观察者模式,只需让主体对象实现 SplSubject ,观察者对象实现 SplObserver,并实现相应方法即可。
【二】UML类图
【三】示例代码
User.php
namespaceDesignPatterns\Behavioral\Observer;
/**
*观察者模式:被观察对象(主体对象)
*
*主体对象维护观察者列表并发送通知
*
*/
classUserimplements\SplSubject
{
/**
*userdata
*
*@vararray
*/
protected$data=array();
/**
*observers
*
*@var\SplObjectStorage
*/
protected$observers;
publicfunction__construct()
{
$this->observers=new\SplObjectStorage();
}
/**
*附加观察者
*
*@param\SplObserver$observer
*
*@returnvoid
*/
publicfunctionattach(\SplObserver$observer)
{
$this->observers->attach($observer);
}
/**
*取消观察者
*
*@param\SplObserver$observer
*
*@returnvoid
*/
publicfunctiondetach(\SplObserver$observer)
{
$this->observers->detach($observer);
}
/**
*通知观察者方法
*
*@returnvoid
*/
publicfunctionnotify()
{
/**@var\SplObserver$observer*/
foreach($this->observersas$observer){
$observer->update($this);
}
}
/**
*
*@paramstring$name
*@parammixed$value
*
*@returnvoid
*/
publicfunction__set($name,$value)
{
$this->data[$name]=$value;
//通知观察者用户被改变
$this->notify();
}
}
UserObserver.php
namespaceDesignPatterns\Behavioral\Observer;
/**
*UserObserver类(观察者对象)
*/
classUserObserverimplements\SplObserver
{
/**
*观察者要实现的唯一方法
*也是被Subject调用的方法
*
*@param\SplSubject$subject
*/
publicfunctionupdate(\SplSubject$subject)
{
echoget_class($subject).'hasbeenupdated';
}
}
【四】测试代码
Tests/ObserverTest.php
namespaceDesignPatterns\Behavioral\Observer\Tests;
useDesignPatterns\Behavioral\Observer\UserObserver;
useDesignPatterns\Behavioral\Observer\User;
/**
*ObserverTest测试观察者模式
*/
classObserverTestextends\PHPUnit_Framework_TestCase
{
protected$observer;
protectedfunctionsetUp()
{
$this->observer=newUserObserver();
}
/**
*测试通知
*/
publicfunctiontestNotify()
{
$this->expectOutputString('DesignPatterns\Behavioral\Observer\Userhasbeenupdated');
$subject=newUser();
$subject->attach($this->observer);
$subject->property=123;
}
/**
*测试订阅
*/
publicfunctiontestAttachDetach()
{
$subject=newUser();
$reflection=new\ReflectionProperty($subject,'observers');
$reflection->setAccessible(true);
/**@var\SplObjectStorage$observers*/
$observers=$reflection->getValue($subject);
$this->assertInstanceOf('SplObjectStorage',$observers);
$this->assertFalse($observers->contains($this->observer));
$subject->attach($this->observer);
$this->assertTrue($observers->contains($this->observer));
$subject->detach($this->observer);
$this->assertFalse($observers->contains($this->observer));
}
/**
*测试update()调用
*/
publicfunctiontestUpdateCalling()
{
$subject=newUser();
$observer=$this->getMock('SplObserver');
$subject->attach($observer);
$observer->expects($this->once())
->method('update')
->with($subject);
$subject->notify();
}
}
【五】总结
观察者模式解除了主体和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。