用户与页面的交互会导致数据状态发生变化,数据状态变化,又需要通过 UI 表现出来。随着页面复杂度的提高,数据变化后要通知的 UI 组件也会变得越来越多。如果不对这一步进行解耦,这部分的代码会变得越来越冗余和复杂,对代码的可读性和可测试性都带来不良的影响。
所以,我们需要对【数据变化】 -> 【UI 变化】这部分的逻辑进行解耦
 
观察者模式介绍 观察者模式(Observer pattern)是一种管理对象及其行为和状态之间的关系的得力工具。
用 JavaScript 的话来说,这种模式的实质就是对可以对程序中的某个对象的状态进行观察,并且在其发生改变时能够得到通知。
所以,这个模式可以解决我们现在面对的问题:”对【数据变化】 -> 【UI 变化】这部分的逻辑进行解耦”
观察者模式中存在两个角色:观察者和被观察者(又名订阅者和发布者)。下面是观察者模式的实现原理。
观察者模式实现原理 可以通过一个实例来了解观察者模式的运行原理。
首先,建立一个描述观察者的类。
1 2 3 4 5 function  Observer ( )  {  this .Update = function  ( )  {        }; } 
 
然后,建立一个描述观察者队列的类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 function  ObserverList ( )  {  this .observerList = []; } ObserverList.prototype.Add = function  (obj )  {   return  this .observerList.push(obj); }; ObserverList.prototype.Empty = function  ( )  {   this .observerList = []; }; ObserverList.prototype.Count = function  ( )  {   return  this .observerList.length; }; ObserverList.prototype.Get = function  (index )  {   if  (index > -1  && index < this .observerList.length) {     return  this .observerList[index];   } }; ObserverList.prototype.Insert = function  (obj, index )  {   var  pointer = -1 ;   if  (index === 0 ) {     this .observerList.unshift(obj);     pointer = index;   } else  if  (index === this .observerList.length) {     this .observerList.push(obj);     pointer = index;   }   return  pointer; }; ObserverList.prototype.IndexOf = function  (obj, startIndex )  {   var  i = startIndex,     pointer = -1 ;   while  (i < this .observerList.length) {     if  (this .observerList[i] === obj) {       pointer = i;     }     i++;   }   return  pointer; }; ObserverList.prototype.RemoveAt = function  (index )  {   if  (index === 0 ) {     this .observerList.shift();   } else  if  (index === this .observerList.length - 1 ) {     this .observerList.pop();   } }; function  extend (extension, obj )  {  for  (var  key in  extension) {     obj[key] = extension[key];   } } 
 
接着,建立一个描述被观察者的类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function  Subject ( )  {  this .observers = new  ObserverList(); } Subject.prototype.AddObserver = function  (observer )  {   this .observers.Add(observer); }; Subject.prototype.RemoveObserver = function  (observer )  {   this .observers.RemoveAt(this .observers.IndexOf(observer, 0 )); }; Subject.prototype.Notify = function  (context )  {   var  observerCount = this .observers.Count();   for  (var  i = 0 ; i < observerCount; i++) {     this .observers.Get(i).Update(context);   } }; 
 
注意这里 Subject 类的 Notify 方法。在观察者模式中,观察者可以观察到被观察者,原因就是:被观察者把观察者的引用存储起来,被观察者可以进行”通告”,对所有观察者进行调用(发送信息)。
 
下面是一个具体的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 <html> <head></head>  <body>     <button id="addNewObserver">Add New Observer checkbox</ button>    <input id="mainCheckbox"  type="checkbox"  />     <div id="observersContainer" ></div>      <script src="./ observer-pattern.js"></script>     <script>         // 我们DOM 元素的引用         var controlCheckbox = document.getElementById(" mainCheckbox"),             addBtn = document.getElementById(" addNewObserver"),             container = document.getElementById(" observersContainer");         // 具体的被观察者         //Subject 类扩展controlCheckbox 类         extend(new Subject(), controlCheckbox);         //点击checkbox 将会触发对观察者的通知         controlCheckbox[" onclick"] = new Function(" controlCheckbox.Notify(controlCheckbox.checked)");         addBtn[" onclick"] = AddNewObserver;         // 具体的观察者         function AddNewObserver() {             //建立一个新的用于增加的checkbox             var check = document.createElement(" input");             check.type = " checkbox";             // 使用Observer 类扩展checkbox             extend(new Observer(), check);             // 使用定制的Update函数重载             check.Update = function (value) {                 this.checked = value;             };             // 增加新的观察者到我们主要的被观察者的观察者列表中             controlCheckbox.AddObserver(check);             // 将元素添加到容器的最后             container.appendChild(check);         }     </script> </body> </html> 
 
至此,观察者模式使用方式简述完毕。
参考 《JavaScript 设计模式与开发实践》 
Learning JavaScript Design Patterns Learning JavaScript Design Patterns 中文版