1.不是示例代码,而是实际应用代码.
2.多个观察者,多个被观察者
3.根据业务情况,观察者与被观察者都是单例的. 统称为 业务逻辑处理单元(Unit)
1.先实现 处理单元的基类 ,主要实现单例
/**
* 所有业务逻辑处理单元的基类,实现了单例化
* @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.现具体实现一个 观察者(以日志为例,这个是最常用的,而且足够简单)
这里对普通观察者进行了一次扩展,允许带一个参数
原因解释一下: 同一个被观察者可能在业务的不同阶段通知同一个观察者, 我想明确告知 观察者 当前阶段之类的信息,
本来可以用被观察者对象的属性来实现,但感觉太绕了,不明确.
/**
* 文本日志处理单元,观察者模式
* @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.根据以上,如果一个被观察者 要想 被 日志观察者 观察(这话可真费劲), 就要实现两个方法, 所以,这就导致了一个接口
/**
* 所有需要日志观察者的被观察者要实现的接口
* @author bluehire
*
*/
interface ILogSubject extends SplSubject{
/**
* 要提供日志文件名
*/
public function getLogFile($params=null);
/**
* 要提供日志内容
*/
public function getLogMsg($params=null);
}
4.现在终于轮到 被观察者了, 所有被观察者都有三个 固定方法,我实现到基类中
/**
* 被观察者(观察者设计模式)的基类,父类为业务逻辑处理单元(实现了单例化)
* @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.开始具体的被观察者,以订单为例
/**
* 订单处理单元,作为 被观察者
* @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
0
上一篇:晒一下我闺女的书单 四年来总结
下一篇:将博客搬至CSDN
相关热门文章
- 根据不同的情况
- 物联网是一个时代的概念...
- android-- A10开发板--Tslib ...
- 如何开启VMware串口
- 策划可行性电子邮件营销方案技...
- phpStudy 2013下载,PHP5开发...
- 草和谐榴社区caoliushequ...
- 灵芝的种类和图片
- 为PHP添加GD库支持
- 赤灵芝和黑灵芝的功效区别...
- LNMP 老是会出现502?
- suse 运用一个shell获取本机和...
- 虚拟机 unix 配置ip
- hp-un 主机新系统读不到磁盘阵...
- mysql出现问题:Starting MySQ...