浅谈php的观察者模式-PHP
一点小吐槽
有时候上网查一点资料,愣是得看个半天,各种名词扑面而来,好像自己在这方面一直都是在打酱油白活了似的。
其实有的时候对的往往是简单的,一目了然的,如果你查资料瞬间各种名词漫天飞舞,那你可以再多找几篇文章去看看了。
百度能查到的资料百分之七十是一模一样的都是互相cv,其他百分之二十就都是抄的手册里的,还有百分之十呢是自己写的,但这百分之十里面吧,又有百分之50喜欢丢名词(听说这样比较有big),还有百分之四十说得不清不楚像是生怕别人会知道了这个知识点了似的,还有百分之五说得清清楚楚简简单单。
还有百分之五就是我这种,什么都不懂又喜欢瞎说误人子弟瞎哔哔的。
在实际应用中,我们能见到的PHP的主要设计模式大概是九种。
其中工厂,单例,观察者模式也是用得比较多的三种模式,所有模式都围绕几个核心转着。
模式让代码更优雅,更容易维护,能更好的应对需求的改变,让代码往高内聚低耦合的道路上更进一步(看项目而言,没有必要一味的追求高内聚低耦合)。
将会遇到的事
撇开观察者模式这几个字不谈,来谈谈可能遇到的事吧。
一个交友网站,你被安排写一个登录模块,很快你就写完了,过了几天,项目经理说,需要用户一登陆这条用户的信息里面的登录时间字段做一下修改,上次登录的时间这个字段也为当前时间。
你三下五除二又给写完了,不就是在登录的时候操作数据库嘛。
过了几天,项目经理说了,需要用户一登陆,就把我们网站的最新活动推送给用户,然后又在操作登录时间字段的代码下面又加了几行。
过了几天经理又说了,用户一登陆,需要给他推送他平常最中意的对象类型,弄十个给他,看他丫的充不充会员,然后又在公司推送活动的代码块下调用别人的模块,获得这个用户的喜好,然后再写推送。
经理又说了,总觉得不够活跃,要不这样,你写块代码,你就造个假,用户一登陆你就让附近的人给他打个招呼。。。。。。
后续可能还有更多,而这只是登录模块,此时这个方法已经是一团乱麻。
半个月后,再把这块代码给你看,或者让你做做修改,加加功能,改改需求什么的,你会鄙视道这哪个傻叉写得玩意啊,都啥啥啥啊这都,随便改一小块整个登录都用不了了。
这是最蠢的写法,好一点就是做成插件的形式,每当有需求打包成一个类,一个供外部调用的方法,执行这个方法就够了,登录模块也就只有几行代码了,且不会影响上下文。还有一种办法就是利用php自带的观察者模式。
引出思想
回头再来看上面这段假设,可以至少得出一个结论,所有需求都是围绕着登录成功后来做的,且每一个动作都相互独立,登陆后要做很多的事情。
再把距离拉远一点,可以看出只要登录成功,部分业务就要开始运行。
在这里我们先可以把这些需求看作是小人儿,用户只要一进门,就会有人喊道有人进来了,该敲锣的敲锣该打鼓的打鼓。
其实这就是观察者模式,只要被观察者作出了响应的改变,观察者们就会有相应的动作。
若观察者模式以这种方式说出来,我想没有几个人会觉得晦涩难懂吧。
但是缺少了big,这不是一个'程序员该有的big',这听起来也太不专业了。
代码
php
提供的两个接口,一个被观察者接口 SplSubject
,一个或多个观察者接口SPLObserver
,和一个可以储存对象的类SplObjectStorage
。
被观察者有三个方法,需要实现这三个方法。
- 一个
attach
可以理解为添加一个观察者。detach
可以理解为删除掉一个观察者。- 一个
notify
里面做循环执行被观察者的update
方法(被观察者被存储在splobjectstorage
类里面),update
方法把本类作为参数传进去。
class Login implements SplSubject{
public $observers= null;
public function __construct()
{
$this->observers= new SplObjectStorage();//这里创建一个存储观察者的对象
}
public function login()
{//单纯做登录操作
$this->notify();//通知观察者
}
public function attach(SplObserver $observer)
{
$this->observers->attach($observer);//添加进一个观察者
}
public function detach(SplObserver $observer)
{
$this->observers->detach($observer);
}
public function notify()//在这个方法里循环调用观察者的update方法
{
$this->observers->rewind();//将内部指针指向开始处
while ($this->observers->valid()) {
$observer= $this->observers->current();//获取当前对象
$observer->update($this);$this->observers->next();//将指针往下走一位
}
}
}
class PushUser implements SplObserver{//用户推送-观察者
public function update(SplSubject $subject)//传进来一个被观察者
{
//写自己的业务逻辑
}
}
class PushNews implements SplObserver{//新闻推送-观察者
public function update(SplSubject $subject)
{
//写自己的业务逻辑
}
}
$user= new Login();//创建一个实现了被观察者的接口类
$user->attach(new PushNews());//传进去一个实现了观察者的接口类
$user->attach(new PushUser());
$user->login();
执行完自己的登录逻辑后,会调用自身的notify
,此时SplObjectStorage
类里已存储了两个对象,notify
中调用观察者的update
方法。
使用Phpstorm
会让你的码字速度变快很多哦。
观察者模式适用场景:
当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。
当对一个对象的改变需要同时改变其它对象,而不知道具体有多少个对象待改变。
当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换句话说,你不希望这些对象是紧密耦合的。
原文链接: 浅谈php的观察者模式-PHP