观察者模式
概述
观察者模式, 是使用频率极高的设计模式, 它用于建立一种对象与对象之间的依赖关系,一个对象发生了改变时将自动通知其他对象,其他对象将做出相应反应。
在观察者模式中,发生改变的对象被称为被观察对象(Subject),而被通知的对象被称为观察者(Observer),观察者与被观察对象是N:1的关系,观察者之间可以没有任何关联, 观察者可以根据需求新增或者删除,便于扩展。
结构
示例(ES6)
class ObserverList {
constructor() {
this.observerList = [];
}
add(observer) {
return this.observerList.push(observer);
}
remove(observer) {
const index = this.observerList.indexOf(observer);
return this.observer.splice(index, 1);
}
}
class Subject {
constructor() {
this.observers = new ObserverList();
}
addObserver(observer) {
return this.observers.add(observer);
}
deleteObserver(observer) {
return this.observers.remove(observer);
}
notify(context) {
this.observers.observerList.map((observer) => {
observer.update(context);
});
}
}
class Observer {
update(context) {
}
}
html
<button>Add a new Observer</button>
<input type="checkbox" id="mainCheckBox">
<div id="container"></div>
js
function extend(source, destination) {
const props = Object.getPrototypeOf(source);
for(var key in source) {
destination[key] = source[key];
}
Object.getOwnPropertyNames(props).map((key) => {
if (key !== "constructor") {
destination[key] = source[key];
}
});
}
function AddObserver() {
const check = document.createElement('input');
check.type = 'checkBox';
extend(new Observer(), check);
check.update = function(value) {
this.checked = value;
}
checkBox.addObserver(check);
container.appendChild(check);
}
const button = document.getElementsByTagName('button')[0];
const checkBox = document.getElementById('mainCheckBox');
const container = document.getElementById('container');
extend(new Subject(), checkBox);
checkBox.onclick = function() {
checkBox.notify(checkBox.checked);
}
button.onclick = AddObserver;
demo实际效果可在codepen查看
发布(Publish)/订阅(Subscribe)
我个人理解是观察者模式中的一种更具体的设计,主要区别在于在观察者(Subscriber)和被观察者(Publisher)之间添加了一个主题(Topic)/事件(Event)的通道,该事件系统代码订阅程序的特定事件,这些事件可以传递特定的参数,这些参数就是订阅者响应事件所需要的参数值,其实现解耦了订阅者与发布者的依赖关系。
结构
示例代码(es5 strict)
'use strict';
var pub = {};
(function(p){
var Event = {};
var id = 0;
p.prototype.subscribe = function(eventName, func) {
if (!Event[eventName]) {
Event[eventName] = [];
}
var subscriber = {
name: eventName,
id: id,
func: func
};
Event[eventName].push(subscriber);
return subscriber;
};
p.prototype.publish = function(eventName, params) {
var funcCollection = Event[eventName];
var length = funcCollection && funcCollection.length || 0;
while(length--) {
funcCollection[length].func(params);
}
}
p.prototype.unsubscribe = function(event) {
var subscribers = Event[event.name];
var length = subscribers.length;
while (length--) {
if (subscribes[length].id === event.id) {
subscribers.splice(length, 1);
}
}
}
})(pub)