PHP设计模式——观察者模式

前言

知识就是做为观察者所得到的结论,通过科学培训的观察者会为咱们提供全部能感知的现实。设计观察者模式是为了让一个对象跟踪某个状态,知道状态什么时候改变,一旦状态改变,全部订阅对象都能获得通知。若是须要保证一个状态的一致性(好比说:状态触发类的应用),可是这个给定状态可能有多个不一样的用户等级,这种状况下观察者模式就很适用,并且颇有帮助,各司其职。利用观察者模式能够维护一致性,同时记录建立一个给定的状态的对象个数。php

观察者模式很直观。何须让多个对象建立或跟踪一个给定的状态呢?若是由一个对象完成这个工做,而后通知其余可能用到这个状态的对象,这样会合理得多。html

使用SPL实现观察者模式

一、可用于观察者设计模式的3个SPL接口/类以下:
● SplSubject
● SplObserver
● SplObjectStoragesql

1.一、SplSubjectthinkphp

<?php

namespace common\observer;

use Yii;

/**
 * SplSubject.
 *
 */
interface SplSubject
{
    /*SplSubject 接口*/
    public function attach (SplObserver $observer);
    public function detach (SplObserver $observer);
    public function notify ();
}

注意这个SplSubject 接口指定attach()和detach()方法参数中$observer的数据类型必须是一个SplObserver 对象。设计模式

1.二、SplObserver数据结构

SplObserver 接口只有一个update()方法,以下所示:函数

<?php

namespace common\observer;

use Yii;

/**
 * SplObserver
 *
 */
interface SplObserver
{
    /*更新方法*/
    public function update (SplSubject $subject);
}

update()方法对于观察者模式相当重要,由于它会获得Subject状态的最新变化,并交给观察者实例。this

1.三、SplObjectStoragespa

SplObjectStorage 类与观察者设计模式没有内在的关系,不过经过它其内置的attach()和detach()方法能够很方便的将观察者实例与一个主题实例相关联以及解除关联。.net

<?php

namespace common\observer;

use Yii;

/**
 * SplObjectStorage 存储对象的类
 * 
 * @property string $storage 存储对象
 * 
 */
class SplObjectStorage
{    
    public $storage;

    //增长方法
    
    public function attach(SplObserver $observer)
    { 
        $this->storage[] = $observer;
    }

    //删除方法

    public function detach(SplObserver $observer)
    {  
        if(is_int($idx = array_search($observer, $this->storage)))
        {
            unset($this->storage[$idx]);
        }
    }
}

注释:若是直接用PHP类库的SplObjectStorage类的话,1.3能够不看了,只须要把1.4里面的$this->observers = new SplObjectStorage();修改成$this->observers = new \SplObjectStorage();(缘由能够去了下PHP的解命名空间和文件加载机制。参考资料),notify方法里的$this->observers->storage修改成$this->observers便可。

1.四、SPL具体主题

SplSubject接口不包括获取方法和设置方法,不过这也是观察者设计模式中的一部分,因此须要增长获取方法和设置方法。设置方法setData()包含一个参数,这是要增长的任何类型的数据。获取方法getData()存储当前的主题状态,由具体观察者用来更新观察者数据。
另外还增长了setObservers()方法。并非在构造函数中设置SplObjectStorage()实例,也没有在setData()方法中设置观察者实例,这里实现了一个单独的setObservers()方法,能够提供更轻松的耦合,并容许有多组观察者。

<?php

namespace common\observer;

use Yii;
 
//ConcreteSubject
 
class ConcreteSubject implements SplSubject
{
 
    private $observers,$data;
 
    public function setObservers()
    {
 
        //sqlObjectStorage 专门用来存储对象的类
 
        $this->observers = new SplObjectStorage();


    }

    //添加观察者
 
    public function attach(SplObserver $observer)
    {
 
        $this->observers->attach($observer);
 
    }
 
    //剔除观察者
 
    public function detach(SplObserver $observer)
    {
 
        $this->observers->detach($observer);
 
    }
 
    //通知notify

    public function notify()
    {  
        foreach ($this->observers->storage as $key =>$observer) { 
            $observer->update($this);
        }
 
    }

    //设置方法

    public function setData($dataNow)
    { 
        $this->data=$dataNow;
    }

    //获取方法

    public function getData()
    {   
        return $this->data;
    }
 
}
 
?>

1.五、SPL具体观察者

用于实现更新函数来更新关联的观察者实例。

<?php


namespace common\observer;

use Yii;
 
//ConcreteObserver
 
class ConcreteObserver implements SplObserver
{
 
    public function update(SplSubject $subject)
    {  
        echo $subject->getData()."</br>";
    }
 
}
 
?>

(附加的普通用户具体观察者)

<?php


namespace common\observer;

use Yii;
 
//Userbservers
 
class UserObserver implements SplObserver
{
 
    public function update(SplSubject $subject)
    {
 
        echo '我是普通用户,请给我对应的普通用户服务';
 
    }
 
}
?>

1.六、SPL客户

“SPL”Client 类只是一个标准客户。这个客户按照SPL接口向具体主题和观察者发出多个请求,不过本身并无实现SPL类和接口。

<?php


namespace common\observer;

use Yii;
 
//Client

class Client
{
 
    public function __construct()
    {
        echo "<h3> 创造新的具体观察者,新的具体主体:</h3>";

        $ob1 = new ConcreteObserver();
        $ob2 = new ConcreteObserver();
        $ob3 = new ConcreteObserver();

        $Subject = new ConcreteSubject();
        $Subject->setObservers();
        $Subject->setData("这是你的数据!");
        $Subject->attach($ob1);
        $Subject->attach($ob2);
        $Subject->attach($ob3);

        $Subject->notify();

        echo "<h3>删除ob3,结果是ob1和ob2的通知:</h3>";
        $Subject->detach($ob3);
        $Subject->notify();

        echo "<h3>剩余的数据和附加数据还有删除ob2,结果是ob1和ob3的通知:</h3>";
        $Subject->setData("更多的数据,只有ob1和ob3是须要的");
        $Subject->attach($ob3);
        $Subject->detach($ob2);
        $Subject->notify();
  
        echo "<h3>剩余数据和附加新数据,结果是ob1和ob3还有“新数据”的通知:</h3>";
        $Subject->attach(new \common\observer\UserObserver);
        $Subject->notify();
    }
 
}
 
?>

1.七、Client的调用输出以下:

调用:$worker=new commonobserverClient();

输出:
图片描述

总结分析

这里SplObjectStorage类是我本身写的,贴出来分享一下。PHP5.1.0以及更高的版本有不少特性,其中之一就是提供了一组能够用于观察者的设计模式的接口。能够研究一下怎么使用,SplObserver接口以及SplSubject和SplObjectStorage接口,利用这些接口,构建观察者模式简直易如反掌。“SPL”是标准PHP类库(Standard PHP Library)的简写,这个库中包括一组解决标准问题的接口和类。参考手册

相关资料

关于观察者模式
利用 SPL 快速实现 Observer 设计模式
PHP SPL标准库之数据结构对象容器(SplObjectStorage)

相关文章
相关标签/搜索