不知你看完「撩妹三部曲」(
撩妹技术三部曲之”设计模式
“、
撩妹技术三部曲之“架构
”、
撩妹技术三部曲之”框架
“)这三篇文章是什么样的感受,我反正是觉得没大讲明白。这种抽象的概念,如果没有亲身实践的话,就好像早上背的英语单词,晚上就忘干净了。其实,
设计模式
也好,框架、架构也罢,都是「产品日益增长的需求和程序员落后的生产力之间矛盾」的产物。正是这些「套路」,解放了程序员的双手,使得他们在与产品经理的长期斗争中侥幸存活了下来。
今天要介绍的观察者模式,作为著名的23种设计模式之一,就是一种常见的「套路」。观察者模式里,有一个被观察者,有一群观察者,当被观察者的状态发生改变的时候,观察者就能及时的观察到这个变化。
具体到代码里,如果一个模块的一举一动,会影响很多模块的功能,就可以使用观察者模式。举个例子,假如你的APP有「用户账号」的模块,其他很多模块都依赖于这个模块(比如发表评论、上传图片之类的操作,都需要获取当前的用户名)。一旦用户注销了账户,那么这些依赖于「用户账号」的模块都必须做出相应的改变。
我们先看下「年轻的」程序员不用观察这模式是如何实现这个需求的。用户点了「注销账号」之后,他费尽心思罗列了所有对「用户账号」模块感兴趣的模块,找到它们「处理用户注销」的代码,然后一个一
个发出通知。于是就有了下面的代码:
def onUserLogout():
//通知朋友圈用户注销了
Moments.onUserLogout()
//通知个人相册用户注销了
Photos.onUserLogout()
//通知我的钱包用户注销了
Wallet.onUserLogout();
….
一个有追求的程序员,看到这样的代码是会疯掉的。为什么?用行话讲,就是这样的代码,没有「解耦」,可维护性太差了。现在大家都是一人一个模块独立开发,如果互相依赖的话,必然会造成「我改了一行代码,你那里却产生了BUG」这种悲剧发生。更何况,哪天增加了一个Favorites模块,岂不是要把这段古董代码翻出来再改一遍?真是没完没了了。
观察者模式怎么做呢?
首先要分清角色。很明显,这个例子里,各个业务模块就是观察者,「用户账号」模块是被观察者。观察者迫切想知道被观察者的一举一动,包括「用户登录」、「用户注销」之类的事件。
其次是抽象接口。之前的文章讲过,接口是一系列能力的集合。这个例子里,所有的观察者,在被观察者眼中应该是一样的,它们都具有「处理用户注销账号」这样的能力,所以我们应该提炼出这样一个接口,来代表所有的观察者。
最后是注册和通知。每当有一个对「用户账号」感兴趣的模块上线了,就要把自己注册给被观察者。被观察者那里存了一份已经注册的观察者清单,当它们感兴趣的事情发生的时候,被观察者只需要把清单里的观察者过一遍,一一通知就好了。
def onUserLogout():
for observer in all_observers:
//依次遍历所有的观察者,通知它们
observer.onUserLogout()
有什么区别吗?区别大了。这么一来,「用户账号」再也不用关心找不到各个具体的业务模块啦,它只认识观察者,至于某个观察者姓甚名谁,对不起,不重要。
即使有了新的业务模块加进来,它只需要实现onUserLogout这个接口,注册给「用户账号」模块,然后在「用户注销」这个事件发生的时候,坐等通知就行了。你甚至可以把「用户账号」这个模块独立出来,做成SDK给别人用。
观察者模式遍布在程序世界的各个角落。很多APP都有全局的设置项,就是典型的被观察者。比如网易新闻的夜间模式,当用户切换成夜间模式之后,被观察者会通知所有的观察者「设置改变了,大家快蒙上遮罩吧」。QQ消息推送来了之后,既要在通知栏上弹个推送,又要在桌面上标个小红点,也是观察者与被观察者的巧妙配合。
观察者模式存在的意义就是「解耦」,它使观察者和被观察者的逻辑不再搅在一起,而是彼此独立、互不依赖。话说回来,程序员对于「解耦」的追求,是没有止境的,即使冒着需求延期的生命危险,他们也会去做。请你们多多理解。
登录 | 立即注册