先通过几个生活场景来体会观察者设计模式的好处:
1. 智行App抢火车票,只要你加入了抢票队伍,就不用一直盯着,下单了会直接发信息通知你。
2. 去饭店吃饭,你不用守在厨师旁边,告诉厨师你的号码,以及要点什么菜,然后坐在饭店里刷自己的手机就好,饭菜好了厨师会直接叫你的号码。
3. 某个女孩某次面见你,装扮得极其漂亮,让你一眼就爱上了。然后随后她的一举一动,就可能有时让你欣喜若狂,有时又让你黯然神伤。
如果去用程序代码来实现上面场景的特点,该怎么写呢?
这里我们就拿第二个示例来实践吧。
为了简便,我们这里将餐馆、厨师、服务员统一抽象成一个餐馆类,简单理解成食物提供方,所有顾客都抽象成顾客类,实现程序如下:
<?php
class Restaurant{
private $guestArr;
/**
* 顾客刚下单,等待饭菜
* @param Guest $obj
*/
public function addGuest(Guest $obj){
$this->guestArr[] = $obj;
}
/**
* 顾客的饭菜已经送到了
* @param Guest $obj
*/
public function removeGuest(Guest $obj){
foreach($this->guestArr as $key => $item){
if( get_class($obj) == get_class($item) ){
unset($this->guestArr[$key]);
}
}
}
/**
* 顾客饭菜刚炒好,通知顾客取餐
*/
public function notify(){
foreach($this->guestArr as $item){
$item->fetchFood();
}
}
}
interface Guest{
public function fetchFood();
}
class A implements Guest{
public function fetchFood()
{
echo get_class($this)." start to fetch food<br>";
}
}
class B implements Guest{
public function fetchFood()
{
echo get_class($this)." start to fetch food<br>";
}
}
$restaurant = new Restaurant();
//A客人来点餐了
$restaurant->addGuest(new A);
//A客人饭菜好了,通知取餐
$restaurant->notify();
上面程序有观察者设计模式的中心思想,但例子却不够贴切于观察者模式。
为什么这么说呢?
观察者设计模式,是说A、B、C、D等观察者都有关注某个主题,然后主题有变化的时候,观察此主题的观察者A、B、C、D等就会都收到通知。
上面顾客点餐的例子,实际生活中餐馆里厨师通知取餐,都是一个个通知的,也就是说这个例子里,观察者始终只有一个,通知取餐,一时间也只有一个顾客去取餐。
如果说多人同时点了番茄炒鸡蛋,然后厨师都放一起炒了,然后分开装盘,通知“番茄炒鸡蛋”已好,然后那些点了番茄炒鸡蛋的人,就会同时来取餐。这种情景,就比上面的程序例子,更加贴切于观察者设计模式了:观察者有多个。
好了,现在我们根据上面程序代码,先抽取出观察者设计模式的主要内容,然后再来个更加实际的开发例子来实践。
Restaurant类,就相当于观察者设计模式中的主题,顾客就相当于其中的观察者,区分谁是主题谁是观察者,最简单的方法,就是看哪一方要发起通知。
找出主题的诀窍:发起通知的一方,就是主题。
然后把上面程序里Restaurant改成Subject,Guest替换成Observer,fetchFood方法改成update,基本也就是你网上看到的大多数观察者设计模式的程序示例了(为了简单,本文抛开了抽象类,直接用的具体类)。
最后我们再来一个实际开发经常遇到的例子来实践,加强对观察者模式的理解。
开发示例:用户注册成功,给用户发邮件,给用户手机发短信,给用户发送站内信,给用户送初始福利。
以前可能这样开发:
if( $resiter_result ){
$emailService = new EmailService();
$emailService->sendEmail();
$mobileService = new mobileService();
$mobileservice->sendMessage();
$modelNote = Model('InsiteNote');
$modelNote->addNote();
...
}
后面随着功能需求的拓展和变动,例如注册成功后,还要给用户送积分,给用户自动关注某些其它用户等等,最终就导致上面那一块的代码,冗长而又臃肿不堪,维护难度逐渐升级。
翟码农用观察者设计模式后,主体代码就如下:
class Client{
public function registerSucceed(){
$subject = new Subject();
$subject->addObserver(new Email());
$subject->addObserver(new Mobile());
$subject->addObserver(new Note());
$subject->notify();
}
}
$client = new Client();
$client->registerSucceed();(全部代码可在文末git地址处下载)
发送邮件、发送短信、发送站内信等操作就在各自的观察者类之内,从而达到一种“解耦”的效果。
git地址:待补充
本文为翟码农个人博客里有关设计模式的原创文章,转载请注明出处:http://www.zhai14.com/blog/design-pattern-of-observer-analyzed-with-simple-thought.html