我们常常会做到这样的一种效果,例如A被点击之后,要求B和C会执行特定的行为。
画图什么的很烦,下面举个简单的例子:
var DomA = document.getElementById("divA");
var DomB = document.getElementById("divB");
var DomC = document.getElementById("divC");
DomB.action = function(){
alert("I'm DomB, I know DomA be clicked");
}
DomC.action = function(){
alert("I'm DomC, I know DomA be clicked")
}
DomA.onclick = function(){
DomB.action();
DomC.action();
}
以上就是观察者模式的简单原理演示,是不是很简单?当然只是流程式的表达意思啦,有点事件监听的味道。看着像是DomA去主动通知DomB和DomC。
OK,清楚简单的原理之后,以下我们就用面向对象的方法来写一个关于观察者模式的片断。
首先,我们要清楚需要些什么?
1、需要一个用来保存观察者的队列,可以用一个数组来保存。
2、需要一个可以方便操作以上观察者队列的类,这样我们就可以方法添加和删除观察者了。
//这是一个操作观察者的类
function ObList(){
this.list = [];
}
//我习惯把方法写到函数的原型链上,因为这样可以节省内存开支。
//统计观察者的个数的方法
ObList.prototype.Count = function(){
return this.list.length;
}
//增加观察者对象的方法
ObList.prototype.Add = function(object){
if(object){
return this.list.push(object);
}
}
//获取指定的观察者对象的方法
ObList.prototype.Get = function(index){
//判断index是否在数组长度范围之内
if(index > -1 && index<this.list.length){
return this.list[index];
}
}
当然,上面只写了三个简单的方法,只是为了演示本例,可以按自己需要添加更多的方法。
好了,接着,我们需要定义一个Subject类,这个类的目的在于处理被观察者与观察者之间的关系和操作。大概需要以下功能:
1、添加观察者对象
2、获取观察者对象
3、通知观察者
前两者就可以引用刚才的ObList类的实例:
//这是一个主题类
function Subject(){
this.observers = new ObList();
}
//通知观察者的方法
Subject.prototype.Notify = function(context){
if(context){
var ob_count = this.observers.Count();
for(var i = 0; i < ob_count; i++){
this.observers.Get(i).Action(context);
}
}
}
//增加观察者的方法
Subject.prototype.AddObserver = function(observer){
if(observer){
this.observers.Add(observer);
}
}
好,“前戏”已经准备好了,我们还未至于急于进入,呵呵,有没发觉少了些什么?
我们这些“前戏”不仅是给某个对象而准备的,也不是给永远仅属于某个对象的。他可以用到A,B,C...对象。
那么,这些方法我们很有可能重用。以下,我们准备一个继承函数,可以把这些方法添加到任意对象上。以后用起来就随心所欲啦。
//这是一个非常经典又普通的继承函数,浅拷贝
function Inherits(base,extension){
for(var property in base){
extention[property] = base[property];
}
//这里省略了异常判断
}
以下开始运用我们前面的代码:
var d = window.document;
var DomA = d.getElementById("divA");
var DomB = d.getElementById("divB");
var DomC = d.getElementById("divC");
//让DomA对象继承Subject方法
Inherits(DomA,new Subject());
//设置DomB对象的action方法
DomB.Action = function(msg){
this.innerHTML = "I'm DomB, I get a message:" + msg;
}
//同样地,设置DomC对象的action方法
DomC.Action = function(msg){
this.innerHTML = "I'm DomC, I get a message:" + msg;
}
//把DomB和DomC添加为DomA的观察者
DomA.AddObserver(DomB);
DomA.AddObserver(DomC);
//让DomA对象通过onclick事件去触发他的Notify方法
DomA.onclick = function(){
this.Notify("DomA be clicked");
}
整个例子演示完毕,其实就是把观察者放到一个数组里,然后被观察者通过事件(onclick)触发(Notify)去遍历观察者(observer)的指定方法(action)。