先通过几个生活场景来体会观察者设计模式的好处:
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