php设计模式(4) 观察者模式
概述
观察者模式属于 类行为 型模式。
一些面相对象的编程方式提供了一种构建对象间复杂网络互联的能力。当对象们链接在一起时,他们就可以相互提供服务和信息
通常来说,当摸一个对象的状态发生改变是,你仍然需要对象之间的相互通信。但是出于各种原因,你也许并不愿意因为代码的环境的改变而对代码做大的修改。也许你只想根据你的具体应用环境而改进代码。或者你只想简单的重构通信代码来避免类和类之间相互依赖的从属关系。
问题
当一个对象的状态发生改变时,你如何通知其他对象?
解决
观察者模式:定义对象间一对多的依赖关系,当一个对象的状态改变时,所有依赖他的对象都会得到通知并自动更新。
适用性(在以下任意情况均可使用)
- 当一个抽象模型有两个方面,一个方面依赖另一个方面。将两者封装在独立的对象中使他们可以各自独立的改变和复用。
- 当一个对象改变时,需要同时改变其他对象,但又不知道具体有多少对象待改变。
- 当一个对象必须通知其他对象,而又不能假定其他对象是谁。
模板成员
目标(被观察者) : 目标知道所有观察者。可以有任意个观察者观察同一个目标。提供注册、删除观察者对象的接口。
具体目标(具体被观察者) : 实现目标中定义的方法,对观察者进行操作。
观察者 : 为那些在 目标 状态改变时,需要获得通知的对象定义一个更新接口。
具体观察者 : 实现观察者定义的接口,保持自身状态和 目标 一致。
优点
- 观察者模式可以实现表示层和数据逻辑层的分离。
- 观察者模式 降低了 目标 和 观察者之间的耦合。
- 观察者模式更符合开闭原则
代码实现
目标 和 观察者(使用了 php spl 提供的接口)
<?php
interface SplSubject{
public function attach(SplObserver $observer);//注册观察者
public function detach(SplObserver $observer);//释放观察者
public function notify();//通知所有注册的观察者
}
interface SplObserver{
public function update(SplSubject $subject);//观察者进行更新状态
}
具体目标(被观察者)
class News implements SplSubject
{
public $pid = 0;
public $observers = [];
public function __construct($pid)
{
$this->pid = $pid;
}
/**
* 添加一个观察者
*
* @param \SplObserver $observer
*/
public function attach(SplObserver $observer)
{
$this->observers[strval($observer)] = $observer;
}
/**
* 删除一个观察者
*
* @param \SplObserver $observer
*/
public function detach(SplObserver $observer)
{
if (array_search($observer, $this->observers, true)) {
unset($this->observers[strval($observer)]);
}
}
/**
* 当状态改变时 通知所有观察者
*/
public function notify()
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
/**
* 相当于改变状态的方法 改变状态后调用 notify
*/
public function read()
{
echo "阅读了 product id " . $this->pid . " 的文章";
$this->notify();
}
}
具体观察者
class NewsClick implements SplObserver
{
/**
* 接收到通知后你做什么由你来决定
*
* @param \SplSubject $subject
*/
public function update(SplSubject $subject)
{
echo "<hr>";
echo 'product ID' . $subject->pid . '点击量加1';
}
/**
* 这个模式方法让我用了做 key 了 你随意
*
* @return string
*/
public function __toString()
{
return "news_click";
}
}
调用
$news = new News(100);
$click_news = new NewsClick();
$news->attach($click_news);
$news->read();
结果
阅读了 product id 100 的文章<hr>product ID100点击量加1
网友评论