PHP 观察者模式 的真正实现

1.不是示例代码,而是实际应用代码.
2.多个观察者,多个被观察者
3.根据业务情况,观察者与被观察者都是单例的. 统称为 业务逻辑处理单元(Unit)

1.先实现 处理单元的基类 ,主要实现单例
<?php
/**
 * 所有业务逻辑处理单元的基类,实现了单例化
 * @author bluehire
 *
 */
class SUnit {
    
    /**
     * 禁止实例化
     */
    protected function __construct(){
    }
    
    /**
     * 获取本类单例的方法,公开
     *
     * @return SUnit
     */
    public static function instance() {
        //延迟绑定的句柄,子类单例,而不是基类
        if(static::$handle){
            return static::$handle;
        }
        
        //这个是延迟绑定的,运行时的子类的类名
        $class = get_called_class();
        static::$handle = new $class();
        return static::$handle;
    }
}

2.现具体实现一个 观察者(以日志为例,这个是最常用的,而且足够简单)
  这里对普通观察者进行了一次扩展,允许带一个参数
  原因解释一下:  同一个被观察者可能在业务的不同阶段通知同一个观察者,  我想明确告知 观察者 当前阶段之类的信息,
   本来可以用被观察者对象的属性来实现,但感觉太绕了,不明确.
<?php
/**
 * 文本日志处理单元,观察者模式
 * @author bluehire
 *
 */
class ULog extends SUnit implements SplObserver {
    protected static $handle; //单例句柄
    
    /**
     * 得到了被观察者的一个通知
     * @see SplObserver::update()
     */
    public function update(SplSubject $object,$params=null){
        //需要被观察者提供一个日志文件名
        $file=$object->getLogFile($params);
        
        //需要被观察者提供一个日志内容
        $msg=$object->getLogMsg($params);
        
        //具体干活
        writeLog($file, $msg);    
    }
}


3.根据以上,如果一个被观察者 要想 被  日志观察者 观察(这话可真费劲), 就要实现两个方法,  所以,这就导致了一个接口
<?php
/**
 * 所有需要日志观察者的被观察者要实现的接口
 * @author bluehire
 *
 */
interface ILogSubject extends SplSubject{
    /**
     * 要提供日志文件名
     */
    public function getLogFile($params=null);
    
    /**
     * 要提供日志内容
     */
    public function getLogMsg($params=null);
}

4.现在终于轮到 被观察者了, 所有被观察者都有三个 固定方法,我实现到基类中
<?php
/**
 * 被观察者(观察者设计模式)的基类,父类为业务逻辑处理单元(实现了单例化)
 * @author bluehire
 *
 */
class SSubject extends SUnit{
    //当前被观察者的所有观察者
    private $observers=array();
    
    /**
     * 增加一个观察者
     * @param SplObserver $observer
     * @return SSubject
     */
    public function attach(SplObserver $observer){
        $this->observers[]=$observer;
        return $this;
    }
    
    /**
     * 取消一个观察者,这个不常用
     * @param SplObserver $observer
     * @return SSubject
     */
    public function detach(SplObserver $observer){
        $idx = array_search ( $observer, $this->observers, true );
        if ($idx) {
            unset ( $this->observers [$idx] );
        }
        return $this;
    }
    
    /**
     * 通知所有观察者
     * @param 可以带一个参数,发送给所有观察者,观察者会将此参数用于回调被观察者的方法
     * @return SSubject
     */
    public function notify($params=null){
        foreach ( $this->observers as $observer ) {
            $observer->update ( $this,$params );
        }
        return $this;
    }
}

5.开始具体的被观察者,以订单为例
<?php
/**
 * 订单处理单元,作为 被观察者
 * @author bluehire
 *
 */
class UOrder extends SSubject implements ILogSubject{
    protected static $handle; //单例句柄
    
    /**
     * 单例,
     * @see SUnit::instance()
     * @return UOrder
     */
    public static function instance(){
        //附加文本日志观察者
        parent::instance()->attach(ULog::instance());
        return self::$handle;
    }
    
    //所有观察者
    private $observers=array();
    
    /**
     * 为日志观察者提供日志文件名
     * @see ILogSubject::getLogFile()
     */
    public function getLogFile($params=null){
        return 'order';
    }
    
    /**
     * 为日志观察者提供日志内容
     * @see ILogSubject::getLogMsg()
     */
    public function getLogMsg($params=null){
        return $params;
    }
    
    
    
    public function something(){
        //......
        $this->notify(array('a'=>1));
    }
}

以上程序实测通过,部分代码请自行修改(如dump,writeLog),

现在说适用范围: 设计 模式这东西,绝对不是随便就可以用的, 简单业务逻辑使用这东西就是个找死.我这里也是因为业务复杂到应该使用一部分设计模式
多个观察者,多个被观察者 才需要使用这个模式 ,


未完事项: 我仍在纠结,要不要使用观察者模式, 相比 过程化的消息通知机制(  被观察者 逐个 通知 观察者,使用 设计 好的 接口), 体会不到好处.

欢迎讨论 Q:31008088



<script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
阅读(92) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值