您的位置:首页 > Web前端 > JavaScript

js实现观察者模式

2015-10-16 10:07 471 查看
基本概念介绍

观察者(observer) 模式广泛用于客户端Javascript编程中。所有的浏览器事件都是该模式的例子。它的另一个名字也称为自定义事件(custom events),与那些由浏览器触发的事件相比,自定义事件表示是由你编程实现的事件。此外,该模式的另一个别名也称为订阅/发布(subscriber/publisher)模式。

设计该模式背后的主要动力是促进形成松散耦合。在这种模式中,并不是一个对象调用另一个对象的方法,而是一个对象订阅另一个对象的特定活动并在状态改变后获得通知。订阅者也称为观察者,而补观察的对象称为发布者或主题。当发生了一个重要的事件时,发布者将会通知(调用)所有订阅者并且可能经常以事件对象的形式传递消息。

示例:杂志订阅

假设有一个发布者paper,它每天出版报纸及月刊杂志。订阅者joe将被通知任何时候所发生的新闻。

该paper对象需要一个subscribers(topics )属性,该属性是一个存储所有订阅者的数组。订阅行为只是将其加入到这个数组中。当一个事件发生时,paper将会循环遍历订阅者列表并通知它们。通知意味着调用订阅者对象的某个方法。故当用户订阅信息时,该订阅者需要向paper的subscribe()提供它的其中一个方法。

paper也提供了unsubscribe()方法,该方法表示从订阅者数组(即subscribers属性)中删除订阅者。paper最后一个重要的方法是publish(),它会调用这些订阅者的方法,总而言之,发布者对象paper需要具有以下这些成员:

1.subscribers 一个数组 2.subscribe() 将订阅者添加到subscribers数组中 3.unsubscribe() 从subscribers数组中删除订阅者 4.publish() 循环遍历subscribers数组中的每一个元素,并且调用他们注册时所提供的方法

所有这三种方法都需要一个topic参数,因为发布者可能触发多个事件(比如同时发布一本杂志和一份报纸)而用户可能仅选择订阅其中一种,而不是另外一种。

由于这些成员对于任何发布者对象都是通用的,故将它们作为独立对象的一个部分来实现是很有意义的。那样我们可将其复制到任何对象中,并将任意给定对象变成一个发布者。

JS里对观察者模式的实现是通过回调来实现的,我们来先定义一个pubsub对象,其内部包含了3个方法:订阅、退订、发布。

var pubsub = {};
(function (q) {

var topics = {}, // 回调函数存放的数组
subUid = -1;
// 发布方法
q.publish = function (topic, args) {

if (!topics[topic]) {
return false;
}

setTimeout(function () {
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;

while (len--) {
subscribers[len].func(topic, args);
}
}, 0);

return true;

};
//订阅方法
q.subscribe = function (topic, func) {

if (!topics[topic]) {
topics[topic] = [];
}

var token = (++subUid).toString();
topics[topic].push({
token: token,
func: func
});
return token;
};
//退订方法
q.unsubscribe = function (token) {
for (var m in topics) {
if (topics[m]) {
for (var i = 0, j = topics[m].length; i < j; i++) {
if (topics[m][i].token === token) {
topics[m].splice(i, 1);
return token;
}
}
}
}
return false;
};
} (pubsub));


使用方式如下:

//来,订阅一个
pubsub.subscribe('example1', function (topics, data) {
console.log(topics + ": " + data);
});

//发布通知
pubsub.publish('example1', 'hello world!');
pubsub.publish('example1', ['test', 'a', 'b', 'c']);
pubsub.publish('example1', [{ 'color': 'blue' }, { 'text': 'hello'}]);


试试多个订阅者订阅同个主题:

//来,订阅一个
pubsub.subscribe('example1', function (topics, data) {
console.log(topics + ": " + data);
});
//来,再订阅一个
pubsub.subscribe('example1', function (topics, data) {
console.log(topics + "******* " + data);
});

//发布通知
pubsub.publish('example1', 'hello world!');


输出:

example1***** hello world!
example1: hello world!


参考:http://www.2cto.com/kf/201210/163500.html
http://www.cnblogs.com/TomXu/archive/2012/03/02/2355128.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: