观察者模式(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复选框的时候.发布者就会向观察者发布消息(这里发布的是他的选中状态). 观察者收到信息后就改变成对应的状态.而实现了全选控制.