<转>PHP设计模式之观察者模式(Observer)
观察者模式: 又称为发布订阅模式,指当一个主体对象(Subject)发生改变时,依赖它的多个观察对象(Observer)都得到通知(notify)并自动更新(update)。
PHP从5.1.0开始提供了SplSubject接口和SplObserver接口,为我们具体应用观察者模式提供了便利。著名的的PHP框架如ZendFramework、Symfony均深度使用了观察者模式。那么究竟在什么场景下需要用到观察者模式呢,以下举例说明:
假如我们应用的订单模块中(Subject=Order<->OrderSubject),用户成功下单之后,我们需要做以下3件事情(Observers):
- 记录业务数据日志 (ActionLogObserver)
- 给用户发送订单确认邮件 (UserMailObserver)
- 给管理人员发订单处理通知邮件 (AdminMailObserver)
<?php
//订单数据对象简单模拟,这个是实际需要被观察的对象(Subject),但是我们将其独立,然后
//通过构造方法传入到我们模式中的Subject中,这样使具体业务更加独立
class Order{
//订单号
private $id;
//用户ID
private $userId;
//用户名
private $userName;
//价格
private $price;
//下单时间
private $orderTime;
//订单数据填充简单模拟,实际应用中可能会读取用户表单输入并处理
public function __set($name, $value){
if (isset($this->$name)){
$this->$name = $value;
}
}
//获取订单属性
public function __get($name){
if (isset($this->$name)){
return $this->$name;
}
return "";
}
}
//被观察者, 负责维护观察者并在变化发生是通知观察者
class OrderSubject implements SplSubject {
private $observers;
private $order;
public function __construct(Order $order) {
$this->observers = new SplObjectStorage();
$this->order = $order;
}
//增加一个观察者
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 getOrder() {
return $this->order;
}
}
//记录业务数据日志 (ActionLogObserver),实际可能还要抽象一层以处理不同的Action(业务操作),这里省略
class ActionLogObserver implements SplObserver{
public function update(SplSubject $subject) {
$order = $subject->getOrder();
//实际应用可能会写到日志文件中,这里直接输出
echo "[OrderId:{$order->id}] [UseId:{$order->userId}] [Price:{$order->price}]";
}
}
//给用户发送订单确认邮件 (UserMailObserver)
class UserMailObserver implements SplObserver{
public function update(SplSubject $subject) {
$order = $subject->getOrder();
//实际应用会调用邮件发送服务如sendmail,这里直接输出
echo "Dear {$order->userName}: Your order {$order->id} was confirmed!";
}
}
//给管理人员发订单处理通知邮件 (AdminMailObserver)
class AdminMailObserver implements SplObserver{
public function update(SplSubject $subject) {
$order = $subject->getOrder();
//实际应用会调用邮件发送服务如sendmail,这里直接输出
echo "Dear Manager: User {$order->userName}(ID:{$order->userId}) submitted a new order {$order->id}, please handle it ASAP!";
}
}
//假设的DB类,便于测试,实际会存入真实数据库
class FakeDB{
public function save($data){
return true;
}
}
//初始化一个订单数据
$order = new Order();
$order->id = 1001;
$order->useId = 9527;
$order->userName = "God";
$order->price = 20.0;
$order->orderTime = time();
//绑定观察者
$subject = new OrderSubject($order);
$actionLogObserver = new ActionLogObserver();
$userMailObserver = new UserMailObserver();
$adminMailObserver = new AdminMailObserver();
$subject->attach($actionLogObserver);
$subject->attach($userMailObserver);
$subject->attach($adminMailObserver);
//向数据库保存订单
$db = new FakeDB();
$result = $db->save($order);
if ($result){
//通知观察者
$subject->notify();
}
Symfony框架之事件监听(EventDispatcher)观察者模式应用简要分析
//相当于被观察者SplSubject
interface EventDispatcherInterface
{
//相当于上面的OrderSubject->notify方法
public function dispatch($eventName, Event $event = null);
//相当于上面的OrderSubject->attach方法
public function addListener($eventName, $listener, $priority = 0);
//添加订阅者,一个订阅者可以监听多个事件
public function addSubscriber(EventSubscriberInterface $subscriber);
//相当于上面的OrderSubject->detach方法
public function removeListener($eventName, $listener);
//移除订阅者
public function removeSubscriber(EventSubscriberInterface $subscriber);
//获得观察者(监听者),主要在dispatch的时候用到
public function getListeners($eventName = null);
//判断是否已经注册了该观察者(监听者)
public function hasListeners($eventName = null);
}
//被观察者的具体实现
class EventDispatcher implements EventDispatcherInterface
{
//具体实现代码省略,大家可以自己去看Symfony代码
//监听者排序,实现了监听处理优先级功能
private function sortListeners($eventName)
{
$this->sorted[$eventName] = array();
if (isset($this->listeners[$eventName])) {
krsort($this->listeners[$eventName]);
$this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]);
}
}
}
//Event,实际上的被观察者超类,所以观察者(监听者)都是注册在相应的Event上面的
class Event
{
//是否已经停止事件继续派发
private $propagationStopped = false;
//让Event能获得当前的派发器
private $dispatcher;
//让Event能够获得自己的名称
private $name;
public function isPropagationStopped()
{
return $this->propagationStopped;
}
//在监听处理方法中调用,阻止剩余监听器的调用
public function stopPropagation()
{
$this->propagationStopped = true;
}
//让Event能获得当前的派发器,这个方法在EventDispatcher::dispatch方法中调用
public function setDispatcher(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}
//返回当前Event的派发器
public function getDispatcher()
{
return $this->dispatcher;
}
public function getName()
{
return $this->name;
}
//让Event能够获得自己的名称,这个方法在EventDispatcher::dispatch方法中调用
public function setName($name)
{
$this->name = $name;
}
}
//一个Event的具体实现,是实际的被观察者,这个Event与前端开发中的Event类似而又有所不同,
//这个Event不需要有用户操作,完全是我们在代码中指定的(如某个对象发生变化的时候抛出一个Event)
namespace Acme\StoreBundle\Event;
use Symfony\Component\EventDispatcher\Event;
use Acme\StoreBundle\Order;
class FilterOrderEvent extends Event
{
protected $order;
public function __construct(Order $order)
{
$this->order = $order;
}
public function getOrder()
{
return $this->order;
}
}
//观察者(监听者)的具体实现,观察者非常自由,SplObserver中约定的update方法命名在Symfony中也
//是完全自定义的,因为在注册观察者的时候会指定相关的具体update方法
use Symfony\Component\EventDispatcher\Event;
class ActionLogListener
{
// ...
public function onSaveAction(Event $event)
{
// ... do something
$order = $event->getOrder();
//实际应用可能会写到日志文件中,这里直接输出
echo "[OrderId:{$order->id}] [UseId:{$order->userId}] [Price:{$order->price}]";
}
}
class UserMailListener
{
// ...
public function onSaveAction(Event $event)
{
// ... do something
$order = $event->getOrder();
//实际应用会调用邮件发送服务如sendmail,这里直接输出
echo "Dear {$order->userName}: Your order {$order->id} was confirmed!";
}
}
// 具体调用
use Acme\StoreBundle\StoreEvents;
use Acme\StoreBundle\Order;
use Acme\StoreBundle\Event\FilterOrderEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
//初始化一个被观察者(这里更像一个管理器)
$dispatcher = new EventDispatcher();
//增加一个store.order事件的监听(观察者)
$actionLoglistener = new ActionLogListener();
$userMailListener = new UserMailListener();
$dispatcher->addListener("store.order", array($actionLoglistener, 'onSaveAction'));
$dispatcher->addListener("store.order", array($userMailListener, 'onSaveAction'));
// 任何方式获得Order对象
$order = new Order();
// order数据的填充处理
// 初始化FilterOrderEvent(具体被观察的对象)
$event = new FilterOrderEvent($order);
// 事件派发,相当于调用了Subject->notify();
// ActionLogListener::onSaveAction() 和 UserMailListener::onSaveAction()均会被调用
$dispatcher->dispatch("store.order", $event);
Symfony Event Dispatcher 特点总结
- 通过增加一个Event的全局命名,使得可以使用一个事件派发器管理多种类型的事件派发(也就是实现了对多个不同的被观察者统一的监听控制)
- 实现了观察者(监听者)的优先级排序功能,这样最终的具体处理变的更加强大
- 增加了订阅者角色,实现了一个对象对多个事件监听的同时注册和统一处理
posted on 2015-10-18 21:01 hahahahahai12 阅读(265) 评论(0) 收藏 举报
浙公网安备 33010602011771号