javascript观察者模式
2010-02-24 15:28 BlueDream 阅读(345) 评论(0) 编辑 收藏 举报观察者模式(Observer).也被称作发布者-订阅者(publisher-subscriber)模式.
这里用个实际中的例子说明.比如报纸行业,这里面有两个主要角色:发行商 和 订阅者.
整个报纸的流程就是:
当新的报纸出现.发行商会通过信息告诉订阅者,最新的报纸已经发行了.请注意订阅.那么订阅者收到这个信息就会做出反应.或者订阅,然后进行一系列的活动(如:查询信息,剪报,给朋友讲解报纸新闻).也可以退订等.
当然发行商和订阅者的沟通方式不是唯一的[如推,拉两种方式].
推: 发行商由于公司规模较大,人员充足,就选择推得方式,用人工挨家挨户的送报纸.比较直接.
拉: 发行商规模较小,只能将报纸放到固定地点,如果有人需要订阅可以去固定地点去订阅.
[简述]
观察者模式就是定义了对象间的一对多关系(一个发行商 对 多个订阅者) 或 多对多关系(一个订阅者 对 多家发行商).
然后当发行商对象的状态改变了(报纸已经印刷完毕),那么订阅者对象就会获取到相关信息而做出对应的反应.
[实例]
多选框全选
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title> AllCheck </title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <script type="text/javascript"> /*! 观察者模式(Observer) */ function ArrayList() { this.aList = []; } ArrayList.prototype.Count = function() { return this.aList.length; } ArrayList.prototype.Add = function(object) { return this.aList.push(object); } ArrayList.prototype.GetAt = function(index) { if(index > -1 && index < this.aList.length) { return this.aList[index]; } else { return undefined; } } ArrayList.prototype.Clear = function() { this.aList = []; } ArrayList.prototype.RemoveAt = function(index) { var m_count = this.aList.length; if(m_count > 0 && index > -1 && index < this.aList.length) { switch(index) { case 0: this.aList.shift(); break; case m_count - 1: this.aList.pop(); break; default: var head = this.aList.slice(0, index); var tail = this.aList.slice(index + 1); this.aList = head.concat(tail); break; } } } ArrayList.prototype.Insert = function(object, index) { var m_count = this.aList.length; var m_returnValue = -1; if(index > -1 && index <= m_count) { switch(index) { case 0: this.aList.unshift(object); m_returnValue = 0; break; case m_count: this.aList.push(object); m_returnValue = m_count; break; default: var head = this.aList.slice(0, index - 1); var tail = this.aList.slice(index); this.aList = this.aList.concat(tail.unshift(object)); // ?? m_returnValue = index; break; } } return m_returnValue; } ArrayList.prototype.IndexOf = function(object, startIndex) { var m_count = this.aList.length; var m_returnValue = -1; if(startIndex > -1 && startIndex < m_count) { var i = startIndex; while( i < m_count ) { if(this.aList[i] == object) { m_returnValue = i; break; } i++; } } return m_returnValue; } ArrayList.prototype.LastIndexOf = function(object, startIndex) { var m_count = this.aList.length; var m_returnValue = -1; if(startIndex > -1 && startIndex < m_count) { var i = m_count - 1; while(i >= startIndex) { if(this.aList[i] == object) { m_returnValue - i; break; } i--; } } return m_returnValue; } /* 观察者 */ function Observer() { this.Update = function() { return; } } /* 发送者 */ function Subject() { this.observers = new ArrayList(); } /* 发送通知 */ Subject.prototype.Notify = function(context) { var m_count = this.observers.Count(); for(var i = 0; i < m_count; i++) { this.observers.GetAt(i).Update(context); } } /* 添加观察者 */ Subject.prototype.AddObserver = function(observer) { if(!observer.Update) { throw 'Wrong observer'; } this.observers.Add(observer); } /* 移除观察者 */ Subject.prototype.RemoveObserver = function(observer) { if(!observer.Update) { throw 'Wrong observer'; } this.observers.RemoveAt(this.observers.IndexOf(observer, 0)); } /* Copy元类继承 */ function inherits(base, extension) { for(var property in base) { try { extension[property] = base[property]; } catch(warning) {} } } /***************** Concrete Subject ***********************/ var mainCheck = document.createElement("INPUT"); mainCheck.type = 'checkbox'; mainCheck.id = 'MainCheck'; mainCheck.style.border = '1px solid red'; inherits(new Subject(), mainCheck); /* 当点击按钮的时候 给相关的观察者发送通知. 观察者接收到通知的时候 改变状态 */ mainCheck['onclick'] = new Function("mainCheck.Notify(mainCheck.checked)"); document.body.appendChild(mainCheck); /********************* Observer *****************************/ var obsCheck1 = document.createElement('INPUT'); var obsCheck2 = document.createElement('INPUT'); obsCheck1.type = 'checkbox'; obsCheck1.id = 'Obs1'; document.body.appendChild(obsCheck1); obsCheck2.type = 'checkbox'; obsCheck2.id = 'Obs2'; document.body.appendChild(obsCheck2); inherits(new Observer(), obsCheck1); inherits(new Observer(), obsCheck2); /* 观察者改变状态 */ obsCheck1.Update = function(value) { this.checked = value; } obsCheck2.Update = function(value) { this.checked = value; } // 将发行者和订阅者(观察者)关联 mainCheck.AddObserver(obsCheck1); mainCheck.AddObserver(obsCheck2); </script> </body> </html>
流程:
两个角色Subject [第一个checkbox]和Observer[其余两个checkbox].
ID为MainCheck的第一个checkbox继承Subject 即文中提到的发布者.其余的两个ID分别为Obs1,Obs2的两个checkbox继承Observer为订阅者.
当点击MainCheck复选框的时候.发布者就会向观察者发布消息(这里发布的是他的选中状态). 观察者收到信息后就改变成对应的状态.而实现了全选控制.