观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
使用观察者模式的好处:
- 支持简单的广播通信,自动通知所有已经订阅过的对象。
- 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
- 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。
首先要把观察者对象创建处理,他有一个消息容器,三个方法,分别是订阅、退订、发布
//将观察者放在闭包中,页面加载时立即执行 var Observer = (function(){ //防止消息队列暴露被篡改,将消息容器作为静态私有变量保存 var messages={}; return{ //注册信息接口 register: function(){}; //发布信息接口 fire:function(){}; //移除信息接口 remove:function(){}; } })();
首先我们需要实现消息注册的方法,注册方法的作用是将订阅者注册的消息推入消息队列中,接受两个参数:消息类型以及相应的处理动作,推入到消息队列时如果消息不存在就要创建一个消息类型并将它放入消息队列中,如果消息存在则推入队列中。
register : function(){ //如果消息不存在则创建一个消息类型 if (typeof messages[type]==='undefined'){ messages[type] = [fn]; //如果消息不存在 }else{ //将动作推入该消息对应的队列中 messages[type].push(fn); } }
发布消息方法是观察者将所有订阅者订阅的消息一次性执行,接受两个参数,消息类型和动作执行时需要的参数,执行消息动作队列之前检验消息的存在,如果没有注册则返回。然后遍历消息执行方法队列,并依次执行。然后将消息类别和传递的参数打包依次传入消息执行方法中。
fire : function(type, args) { //如果消息没被注册,则返回 if (!messages[type]) return; //定义消息信息 var events = { type: type; // 消息类型 args: args || {}//消息携带数据 }, i = 0,//消息动作循环变量 len = messages[type].length;//消息动作长度 //遍历消息动作 for(;i<len;i++){ //依次执行注册的消息对应的动作系列 messages[type][i].call(this.events); } }
最后是消息注销方法,其功能是将订阅者注销的消息从消息队列中删除,需要两个参数,即消息类型以及执行的某一动作,为避免删除消息动作时消息不存在的情况,对消息队列中的消息要进行检验
remove : function(type, fn){ //如果消息动作队列存在 if (messages[type] instanceof Array{ //从最后一个消息动作遍历 var i = messages[type].length-1; for(;i>=0;i--){ // 如果存在该动作则在消息动作序列中移除相应的动作 messages[type][i]===fn && messages[type].splice(i,1); } } }