浅谈javasript 观察者模式

对于密集型前端项目而言,业务的复杂程度会导致代码的耦合非常巨大,如何解耦和更加优雅的实现成为每个前端开发工程师的一个追求的目标。前端MVC,观察者模式,面向接口编程等等方案的提出都为我们解决了一些项目中常常碰到的实际问题。
之前winter大大吐槽过javascript 乱用设计模式的方式,我想观察者模式应用在相对独立的模块之间的解耦不属于此列。加上阿当也在他的微博上说到,会不会使用js的消息通知机制,可以区分js的老手和新手之分。由此可见观察者模式对于一些实际开发者而言还是比较讨好的。
那么具体什么是观察者模式,用通俗易懂的话说,就是模块之间的订阅以及广播。假设有A、B两个模块,相互不知道对方的存在(相互独立),B模块订阅了A模块的通知,这个假如时候A 由于状态的改变会发出广播,那么对模块A 订阅了这个状态的B就执行相应的逻辑。 整个订阅和通知的这个机制始终处于第三方,相当于一个接线员的工作,很像一个观察者,就是所谓的观察者模式。在wiki上有更加详细的解释,感兴趣的同学可以看看 观察者模式wiki
这里引用wiki上的对观察者模式的用途阐述:

引用

  • 当抽象个体有两个相互依赖的层面时,封装这些层面在单独的物件内可将允许程序设计师单独地去变更重复使用这些物件,而不会产生两者之间的交互的问题。
  • 当其中一个物件的变更会影响其他物件,却又不知道多少物件必须被同时变更时。
  • 当物件应该有能力通知其他物件,又不应该知道其他物件的实际细节时

上面提到的观察者用途是否似曾相识?工作中的实际项目是否常见呢?我觉得答案是肯定的,除非你的业务逻辑不需要和任何外界的模块交互。举个很简单的例子来说。目前很流行的SNS站点,大多都有发消息的功能,无论是心情也好,微博也好就拿微博举例子吧。在发消息这个动作进行的过程需要做什么事情?
消息发送成功之后通知主页timeline立马显示那条消息,在自己的发的消息数字上+1,甚至在一些SAP(single page app上)还需要更新我发送的消息 timeline 等等。
同样微博的收听,评论等等功能也一样。
比较耦合的写法就是在发送请求成功过后,依次在callback里执行相应的逻辑。这就使得,发消息的模块,必须要知道他发送成功了必须要通知哪几个模块,并且执行他们的逻辑。
而在观察者模式情况下是怎么做的呢?抽象的说,在发送消息的请求成功返回后,发送广播消息已发送成功,所有订阅了这个类型的广播的模块依次自己去执行自己的对应逻辑。这样每个模块只需要面向和自己有关的广播,处理相应的逻辑。而不用关心自己和其他具体模块交互的逻辑。
那么到底如何实现这个观察者模式呢?
其实在我们理解里以后,发现观察者需要提供的最基本的接口有下面三个:

  • subscribe 订阅
  • fire 发送广播
  • unsubscribe 取消订阅
var observer = (function(){
     var obList = {};
     function subscribe(msgType,callback){
          //订阅广播
          if(!obList[msgType]){
               obList[msgType] = []
          }
          obList[msgType].push(callback);
     }
     function fire(msgType, data){
          //发送广播
          if(obList[msgType]){
               for(var i=0,l=obList[msgType].length;i<l;i++){
                    //发送广播的数据data
                    obList[msgType][i](data);
               }
          }
     }
     function unsubscribe(msgType, callback){
          //取消订阅
          if(obList[msgType]){
               obList[msgType].shift(obList[msgType].indexOf(callback));
          }         
     }
     return {
         'subscribe' : subscribe,
         'fire' : fire,
         'unsubscribe' : unsubscribe
     };
})()

以上代码是为了阐述观察者模式随手写的单例,不推荐直接使用,我甚至都没有自测,只是把实现的大概思想在这里用代码表述了一遍。当然要注意的是,观察者模式如果管理不善的话,也会导致消息类型的以上的msgType的肆意增长,要优雅的使用观察者模式还需要更好的管理这些msgType,或者可以根据观察的对象不同定义一些不同的频道,这样使得即便观察对象多了也便于维护。
使用观察者模式的好处是你只需要通过这样的设计,就可以避免代码里大量的耦合,做到充分解耦,何乐而不为呢?加上现在DOM LEVEL3 event对象也开始支持以前不支持的但却被很多人实现了的customEvent。通过这个方式也可以实现观察者模式,只不过这个方式依赖DOM和事件对象,或是对于过于抽象的组件也许不适合。其实事件监听器(EventListener)也是观察者模式的一种,现实的例子中观察者模式还是很流行的,所以了解这个模式对前端开发来说很有帮助。

你可能感兴趣的:(JavaScript,mvc,设计模式 观察者模式)