PHP设计模式之观察者模式(Observer)详细介绍和代码实例

【意图】

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新【GOF95】 又称为发布-订阅(Publish-Subscribe)模式、模型-视图(Model-View)模式、源-监听(Source-Listener)模式、或从属者(Dependents)模式

【观察者模式结构图】

【观察者模式中主要角色】

1.抽象主题(Subject)角色:主题角色将所有对观察者对象的引用保存在一个集合中,每个主题可以有任意多个观察者。 抽象主题提供了增加和删除观察者对象的接口。
2.抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在观察的主题发生改变时更新自己。
3.具体主题(ConcreteSubject)角色:存储相关状态到具体观察者对象,当具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
4.具体观察者(ConcretedObserver)角色:存储一个具体主题对象,存储相关状态,实现抽象观察者角色所要求的更新接口,以使得其自身状态和主题的状态保持一致。

【观察者模式的优点和缺点】

观察者模式的优点:

1.观察者和主题之间的耦合度较小;
2.支持广播通信;

观察者模式的缺点:

由于观察者并不知道其它观察者的存在,它可能对改变目标的最终代价一无所知。这可能会引起意外的更新。

【观察者模式适用场景】

当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。
当对一个对象的改变需要同时改变其它对象,而不知道具体有多少个对象待改变。
当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换句话说,你不希望这些对象是紧密耦合的。

【观察者模式与其它模式】

1.中介者模式(Mediator):通过封装复杂的更新语义,ChangeManager充当目标和观察者之间的中介者。
2.单例模式(singleton模式):ChangeManager可使用Singleton模式来保证它是唯一的并且是可全局访问的。

【观察者模式PHP示例】

代码如下:

<?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();

/* 添加第一个观察者 */
$observer1 = new ConcreteObserver('Martin');
$subject->attach($observer1);

echo '<br /> The First notify:<br />';
$subject->notifyObservers();

/* 添加第二个观察者 */
$observer2 = new ConcreteObserver('phppan');
$subject->attach($observer2);

echo '<br /> The Second notify:<br />';
$subject->notifyObservers();

/* 删除第一个观察者 */
$subject->detach($observer1);

echo '<br /> The Third notify:<br />';
$subject->notifyObservers();
具体案例:

<?php
 /** 
  * 3.1php设计模式-观测者模式 
  * 3.1.1概念:其实观察者模式这是一种较为容易去理解的一种模式吧,它是一种事件系统,意味 
  *          着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候, 
  *          观察类可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间
  *          紧密耦合的另一种方法
  * 3.1.2关键点:
  *        1.被观察者->追加观察者;->一处观察者;->满足条件时通知观察者;->观察条件
  *        2.观察者 ->接受观察方法
  * 3.1.3缺点:
  * 3.1.4观察者模式在PHP中的应用场合:在web开发中观察者应用的方面很多
  *        典型的:用户注册(验证邮件,用户信息激活),购物网站下单时邮件/短信通知等
  * 3.1.5php内部的支持
  *        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 User implements SplSubject {
    //注册观察者
    public $observers = array();

//动作类型
    CONST OBSERVER_TYPE_REGISTER = 1;//注册
    CONST OBSERVER_TYPE_EDIT = 2;//编辑

/**
     * 追加观察者
     * @param SplObserver $observer 观察者
     * @param int $type 观察类型
     */
    public function attach(SplObserver $observer, $type)
    {
        $this->observers[$type][] = $observer;
    }

/**
     * 去除观察者
     * @param SplObserver $observer 观察者
     * @param int $type 观察类型
     */
    public function detach(SplObserver $observer, $type)
    {
        if($idx = array_search($observer, $this->observers[$type], true))
        {
            unset($this->observers[$type][$idx]);
        }
    }

/**
     * 满足条件时通知观察者
     * @param int $type 观察类型
     */
    public function notify($type)
    {
        if(!empty($this->observers[$type]))
        {
            foreach($this->observers[$type] as $observer)
            {
                $observer->update($this);
            }
        }
    }

/**
     * 添加用户
     * @param str $username 用户名
     * @param str $password 密码
     * @param str $email 邮箱
     * @return bool
     */
    public function addUser()
    {

//执行sql

//数据库插入成功
        $res = true;

//调用通知观察者
        $this->notify(self::OBSERVER_TYPE_REGISTER);

return $res;
    }

/**
     * 用户信息编辑
     * @param str $username 用户名
     * @param str $password 密码
     * @param str $email 邮箱
     * @return bool
     */
    public function editUser()
    {

//执行sql

//数据库更新成功
        $res = true;

//调用通知观察者
        $this->notify(self::OBSERVER_TYPE_EDIT);

return $res;
    }
}

/**
* 观察者-发送邮件
*/
class Send_Mail implements SplObserver
 {
    /**
     * 相应被观察者的变更信息
     * @param SplSubject $subject
     */
    public function update(SplSubject $subject)
    {
        $this->sendMail($subject->email, $title, $content);
    }

/**
     *发送邮件
     *@param str $email 邮箱地址
     *@param str $title 邮件标题
     *@param str $content 邮件内容
     */
    public function sendEmail($email, $title, $content)
    {
        //调用邮件接口,发送邮件
    }
}
?>

(0)

相关推荐

  • php 设计模式之 工厂模式

    本人常用mysql数据库,所以程序只写了mysql的数据库操作类.希望各位高手把另外的类写全,最好能发一份给我. db_mysql.php继承db.php接口,具体实现数据库操作的各种方法 ,如果你确定你的数据库平台不会变的话不用工厂类,直接用这个就行了. 复制代码 代码如下: <?php /** * @author 黄建文 * @version V1.0 * @email hjwtp2005@qq.com * @data 2008-12-16 * =======================

  • php设计模式 Template (模板模式)

    继承关系由于自身的缺陷,被专家们扣上了"罪恶"的帽子."使用委派关系代替继承关系","尽量使用接口实现而不是抽象类继承"等等专家警告,让我们这些菜鸟对继承"另眼相看".其实,继承还是有很多自身的优点所在.只是被大家滥用的似乎缺点更加明显了.合理的利用继承关系,还是能对你的系统设计起到很好的作用的.而模板方法模式就是其中的一个使用范例. GOF给模板方法(Template Method)模式定义一个操作中的算法的骨架,而将一些步

  • PHP设计模式之工厂模式实例总结

    本文实例讲述了PHP设计模式之工厂模式.分享给大家供大家参考,具体如下: 使用工厂模式的目的或目标? 工厂模式的最大优点在于创建对象上面,就是把创建对象的过程封装起来,这样随时可以产生一个新的对象. 减少代码进行复制粘帖,耦合关系重,牵一发动其他部分代码. 通俗的说,以前创建一个对象要使用new,现在把这个过程封装起来了. 假设不使用工厂模式:那么很多地方调用类a,代码就会这样子创建一个实例:new a(),假设某天需要把a类的名称修改,意味着很多调用的代码都要修改. 工厂模式的优点就在创建对象

  • php设计模式 Proxy (代理模式)

    代理,指的就是一个角色代表另一个角色采取行动,就象生活中,一个红酒厂商,是不会直接把红酒零售客户的,都是通过代理来完成他的销售业务.而客户,也不用为了喝红酒而到处找工厂,他只要找到厂商在当地的代理就行了,具体红酒工厂在那里,客户不用关心,代理会帮他处理. 代理模式,就是给某一对象提供代理对象,并由代理对象控制具体对象的引用. 代理模式涉及的角色: 抽象主题角色,声明了代理主题和真实主题的公共接口,使任何需要真实主题的地方都能用代理主题代替. 代理主题角色,含有真实主题的引用,从而可以在任何时候操

  • php设计模式 DAO(数据访问对象模式)

    复制代码 代码如下: <?php /** * 数据访问对象(Data Access Object) 示例 * * @create_date: 2010-01-04 */ class BaseDAO { var $_db = null; var $_table = null; function BaseDAO($config) { $this->_db = new MysqlDB(); // 这里的不能进行操作 } /** * 获取处理 * * @param array $filter // 过

  • php设计模式小结

    1.单例模式 所谓单例模式,也就是在任何时候,应用程序中只会有这个类的一个实例存在.常见的,我们用到单例模式只让一个对象去访问数据库,从而防止打开多个数据库连接.要实现一个单例类应包括以下几点: 和普通类不同,单例类不能被直接实例化,只能是由自身实例化.因此,要获得这样的限制效果,构造函数必须标记为private. 要让单例类不被直接实例化而能起到作用,就必须为其提供这样的一个实例.因此,就必须要让单例类拥有一个能保存类的实例的私有静态成员变量和对应的一个能访问到实例的公共静态方法. 在PHP中

  • 介绍php设计模式中的工厂模式

    问题 你如何能轻松方便地建立这么" 复杂 " 的对象即操作中不需要粘贴复制呢? 解决方法 建立一个工厂(一个函数或一个类方法)来制造新的对象.为了理解工厂的用处, 试想以下的不同之处-- 代码: 复制代码 代码如下: $connection =& new MySqlConnection($user, $password, $database); --使你的代码可扩展和更简洁-- 复制代码 代码如下: $connection =& create_connection();

  • PHP最常用的2种设计模式工厂模式和单例模式介绍

    1.工厂模式 主要作用是降低耦合度. 复制代码 代码如下: abstract class Operation{ abstract public function getValue($num1,$num2); public function getAttr(){ return 1; } } class Add extends Operation{ public function getValue($num1, $num2){ return $num1+$num2; } } class Sub ex

  • php单态设计模式(单例模式)实例

    单态设计模式也叫单例模式: 1.单态设计模式含义: 单态模式的主要作用是保证在面向对象编程设计中,一个类只能有一个实例对象存在.作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例.它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用. 2.单台模式的三个关键点: ① 需要一个保存类的唯一实例的静态成员变量: ②构造函数和克隆函数必须声明为私有的,防止外部程序new类从而失去单例模式的意义: ③必须提供一个访问这个实例的公共的静态方法(通常为

  • php设计模式之简单工厂模式详解

    本文以实例形式较为详细的介绍了PHP设计模式的简单工厂模式,对于进行PHP程序设计来说有很好的借鉴作用.具体如下: 一.概念 简单工厂模式 [静态工厂方法模式](Static Factory Method) 是类的创建模式 工厂模式的几种形态: 1.简单工厂模式(Simple Factory)又叫做 静态工厂方法模式(Static Factory Method) 2.工厂方法模式(Factory Method)又叫做 多态性工厂模式(Polymorphic Factory) 3.抽象工厂模式(A

  • php基础设计模式大全(注册树模式、工厂模式、单列模式)

    废话不多说了,先给大家介绍注册树模式然后介绍工厂模式最后给大家介绍单列模式,本文写的很详细,一起来学习吧. php注册树模式 什么是注册树模式? 注册树模式当然也叫注册模式,注册器模式.之所以我在这里矫情一下它的名称,是因为我感觉注册树这个名称更容易让人理解.像前两篇一样,我们这篇依旧是从名字入手.注册树模式通过将对象实例注册到一棵全局的对象树上,需要的时候从对象树上采摘的模式设计方法.   这让我想起了小时候买糖葫芦,卖糖葫芦的将糖葫芦插在一个大的杆子上,人们买的时候就取下来.不同的是,注册树

  • php设计模式 Factory(工厂模式)

    复制代码 代码如下: <?php /** * 工厂方法模式 * * 定义一个用于创建对象的接口,让子类决定将哪一个类实例化,使用一个类的实例化延迟到其子类 */ /* class DBFactory { public static function create($type) { swtich($type) { case "Mysql": return new MysqlDB(); break; case "Postgre": return new Postg

随机推荐