观察者(Observer)模式是针对回调模式的另外一种扩展。它允许被观察者(Subject,第一个例子中的AClass实例)添加多个观察者。
因此,在被观察者中需要维护一个观察者列表(ObserverList),当数据发生变化时,需要通知所有的观察者。
举例:原型链方式
let Subject = function() {
this.observers = [];
}
Subject.prototype.addObserver = function(obv) {
this.observers.push(obv);
}
Subject.prototype.removeObserver = function(obv) {
let index = -1;
for(let i = 0; i < this.observers.length; i++) {
if(this.observers[i] === obv) {
index = i;
break;
}
}
if(index > 0) this.observers.splice(index, 1);
}
Subject.prototype.notify = function(event) {
for(let obv of this.observers) {
obv.update(event)
}
}
let Observer = function() { }
Observer.prototype.update = function(event) {
console.log(event)
}
举例:面向对象方式
class Subject {
constructor() {
this.observers = [];
}
addObserver(obv) {
this.observers.push(obv);
}
removeObserver(obv) {
let index = -1;
for(let i = 0; i < this.observers.length; i++) {
if(this.observers[i] === obv) {
index = i;
break;
}
}
if(index > 0) this.observers.splice(index, 1);
}
notify(event) {
for(let obv of this.observers) {
obv.update(event)
}
}
}
class Observer {
constructor() { }
update(event) {
console.log(event)
}
}
在业务逻辑中,通过继承的方式去实现观察者的回调逻辑和被观察者的通知逻辑:
举例:原型链方式
let AClass = function() {};
AClass.prototype = new Subject();
AClass.prototype.constructor = AClass;
AClass.prototype.add = function(number) {
this.notify("added " + number);
};
let BClass = function() {};
BClass.prototype = new Observer();
BClass.prototype.constructor = BClass;
// 这种方式进行原型链重载后无法调用父类属性同名函数
let a = new AClass();
let b = new BClass();
a.addObserver(b);
a.add(5);
// added 5
举例:面向对象方式
class AClass extends Subject {
constructor() {
super();
}
add(number) {
super.notify("added " + number);
}
}
class BClass extends Observer {
constructor() {
super();
}
}
class CClass extends Observer {
constructor() {
super();
}
update(event) {
super.update(event)
console.log("SubClass " + event)
}
}
let a = new AClass();
let b = new BClass();
let c = new CClass();
a.addObserver(b);
a.addObserver(c);
a.add(5);
// added 5
// added 5
// SubClass added 5