共计 3393 个字符,预计需要花费 9 分钟才能阅读完成。
Obeserver(观察者)模式
定义
《js 设计模式》中对 Observer 的定义:一个对象(称为 subject)维持一系列依赖于它(观察者)的对象,将有关状态的任何变更自动通知给它们。
《设计模式:可服用面向对象软件的基础》中对 Observer 的定义:一个或多个观察者对目标的状态感兴趣,它们通过将自己依附在目标对象上以便注册所感兴趣的内容。目标状态发生改变并且观察者可能对这些改变感兴趣,就会发送一个通知消息,调用每个观察者的更新方法。当观察者不再对目标感兴趣时,他们可以简单地将自己从中分离。
下面看一个观察者模式的例子:
// 观察者列表
function ObserverList() {
this.observerList = [];
}
ObserverList.prototype.add = function(obj) {
return this.observerList.push(obj);
};
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.indexOf = function(obj, startIndex) {
var i = startIndex;
while(i < this.observerList.length) {
if(this.observerList[i] === obj) {
return i;
}
i++;
}
return -1;
};
ObserverList.prototype.removeAt = function(index) {
this.observerList.splice(index, 1);
};
// 目标
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);
}
};
// 观察者
function Observer(name, subject) {
this.name = name;
this.subject = subject;
this.subscribe(this.subject);
}
Observer.prototype.update = function(context) {
console.log(‘observer:’ + this.name + ‘ content:’ + context);
}
Observer.prototype.subscribe = function(subject) {
this.subject.addObserver(this);
}
var subject1 = new Subject();
var subject2 = new Subject();
var observer1 = new Observer(‘observer1’, subject1);
var observer2 = new Observer(‘observer2’, subject1);
var observer3 = new Observer(‘observer3’, subject2);
subject1.notify(‘999 感冒灵 ’);
subject2.notify(‘999 胃泰 ’);
//observer:observer1 content:999 感冒灵
//observer:observer2 content:999 感冒灵
//observer:observer3 content:999 胃泰
常用的场景
网页的事件绑定
Publish/Subscribe(发布 / 订阅)模式
下面我们来看一个发布订阅的具体实现;
var pubsub={};
(function(q){
var topics={},
subUid=-1,
subscribers,
len;
// 发布广播事件,包含特定的 topic 名称和参数
q.publish=function(topic, args){
if(!topics[topic]){
return false;
}
subscribers=topics[topic];
len=subscribers ? subscribers.length : 0;
while(len–){
subscribers[len].func(topic, args);
}
return this;
};
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 this;
};
})(pubsub);
function log1(topic ,data){
console.log(topic , data);
}
function log2(topic ,data){
console.log(“Topic is “+topic+” Data is “+data);
}
pubsub.subscribe(“sss”,log2);
pubsub.subscribe(“sss”,log1);
pubsub.subscribe(“cccc”,log2);
pubsub.subscribe(‘aaa’, log1);
pubsub.publish(“sss”,”aaaaa1″);
pubsub.publish(“cccc”,”ssssss”);
pubsub.publish(‘aaa’, ‘hahahahah’);
//sss aaaaa1
//Topic is sss Data is aaaaa1
//Topic is cccc Data is ssssss
//aaa hahahahah
区别
Observer 模式要求希望接收到主题通知的观察者或对象必须订阅内容改变的事件。如图:Publish/Subscribe 模式比较观察者模式则多了一个类似于话题调度中心的流程,发布者和订阅者解耦。
观察者模式更像是去咖啡店点咖啡,向店家点一杯咖啡,然后做好后店家会送过来,我和店家是直接有交互的。
发布订阅模式就像是我们微信里面订阅公众号,发布者把文章发布到这个公众号,我们订阅公众号后就会收到发布者发布的文章,我们可以关注和取消关注这个公众号。
实际应用
promise
jquery 的 Callback 内部方法
感兴趣的小伙伴可以移步自己动手实现一个 Promise
JS 设计模式系列文章
JS 设计模式之 Obeserver(观察者)模式、Publish/Subscribe(发布 / 订阅)模式 JS 设计模式之 Factory(工厂)模式 JS 设计模式之 Singleton(单例)模式 JS 设计模式之 Facade(外观)模式 JS 设计模式之 Module(模块)模式、Revealing Module(揭示模块)模式