观察者模式
1.定义
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有的观察者对象,使他们能够自动更新自己。
2. UML图
3.代码示例:
<?php
/**
* 观察者模式
* @package design pattern
*/
/**
* 抽象主题角色
*/
interface Subject {
/**
* 增加一个新的观察者对象
* @param Observer $observer
*/
public function attach(Observer $observer);
/**
* 删除一个已注册过的观察者对象
* @param Observer $observer
*/
public function detach(Observer $observer);
/**
* 通知所有注册过的观察者对象
*/
public function notifyObservers();
}
/**
* 具体主题角色
*/
class ConcreteSubject implements Subject {
private $_observers;
public function __construct() {
$this->_observers = array();
}
/**
* 增加一个新的观察者对象
* @param Observer $observer
*/
public function attach(Observer $observer) {
return array_push($this->_observers, $observer);
}
/**
* 删除一个已注册过的观察者对象
* @param Observer $observer
*/
public function detach(Observer $observer) {
$index = array_search($observer, $this->_observers);
if ($index === FALSE || ! array_key_exists($index, $this->_observers)) {
return FALSE;
}
unset($this->_observers[$index]);
return TRUE;
}
/**
* 通知所有注册过的观察者对象
*/
public function notifyObservers() {
if (!is_array($this->_observers)) {
return FALSE;
}
foreach ($this->_observers as $observer) {
$observer->update();
}
return TRUE;
}
}
/**
* 抽象观察者角色
*/
interface Observer {
/**
* 更新方法
*/
public function update();
}
class ConcreteObserver implements Observer {
/**
* 观察者的名称
* @var <type>
*/
private $_name;
public function __construct($name) {
$this->_name = $name;
}
/**
* 更新方法
*/
public function update() {
echo 'Observer', $this->_name, ' has notified.<br />';
}
}
// 实例化类:
$subject = new ConcreteSubject();
/* 添加第一个观察者 */
$ob1 = new ConcreteObserver('Martin');
$subject->attach($ob1);
echo '<br /> The First notify:<br />';
$subject->notifyObservers();
/* 添加第二个观察者 */
$ob2 = new ConcreteObserver('phppan');
$subject->attach($ob2);
echo '<br /> The Second notify:<br />';
$subject->notifyObservers();
/* 删除第一个观察者 */
$subject->detach($ob1);
echo '<br /> The Third notify:<br />';
$subject->notifyObservers();
4. 具体示例:
<?php
/**
*php内部的支持
* SplSubject 接口,它代表着被观察的对象,
* 其结构:
* interface SplSubject
* {
* public function attach(SplObserver $observer);
* public function detach(SplObserver $observer);
* public function notify();
* }
* SplObserver 接口,它代表着充当观察者的对象,
* 其结构:
* interface SplObserver
* {
* public function update(SplSubject $subject);
* }
*/
/**
* 用户登陆-诠释观察者模式
*/
class Subject implements SplSubject{
private $observers = array();
//订阅
public function attach(SplObserver $observer)
{
if (!in_array($observer,$this->observers)) {
$this->observers[] = $observer;
}
}
//取消订阅
public function detach(SplObserver $observer)
{
if (false != ($index = array_search($observer, $this->observers))) {
unset($this->observers[$index]);
}
}
public function post()
{
//post相关code
$this->notify();
}
public function notify()
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
public function setCount($count)
{
echo "数据量加" . $count."<br>";
}
public function setIntegral($integral)
{
echo "积分量加" . $integral."<br>";
}
}
//观察者
class Observer1 implements SplObserver{
public function update(SplSubject $subject)
{
$subject-> setCount(1);
}
}
class Observer2 implements SplObserver{
public function update(SplSubject $subject)
{
$subject-> setIntegral(10);
}
}
//test case
$subject = new Subject();
$subject->attach(new Observer1());
$subject->attach(new Observer2());
$subject->post();
5.适用情况
a.一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
b.一个对象必须通知其他对象,而并不知道这些对象是谁。需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
6.不足
当观察者类被完全封装后,无法通过改修改类来实现对主题改变的观察,此时,观察者和主题之间相互不知道。此时可以通过委托的方式来解决此问题。