1、观察者模式
观察者模型是非常普遍的一种设计模式,通常会用来在不同系统之间进行解耦。
观察者模式:两种关键对象和三种关键操作
- subject对象:提供三种基本操作方式:被订阅(注册监听方法 register),被取消订阅(移除监听方法 remove),触发事件(notify)
- observers对象:监听 subject 对象事件,然后执行业务主要逻辑
//目标对象的构造函数 function Subject() { this.observerList = []; } //订阅方法 Subject.prototype.register = function(observer) { if (!observer || !observer.handler) { return; } this.observerList.push(observer); } //取消订阅方法 Subject.prototype.remove = function(observer) { var index = this.observerList.indexOf(observer); this.observerList.splice(index, 1); } //触发事件 Subject.prototype.notify = function() { var args = Array.prototype.slice.call(arguments); this.observerList.forEach(observer => { observer.handler && observer.handler.apply(observer, args) }); } //观察者构造函数 function Observer(handlerfn) { this.handler = handlerfn; } //使用示例: //注册一个目标对象 var subject = new Subject(); var ob1 = new Observer(function() { //注册一个观察者 var args = Array.prototype.slice.call(arguments); console.log('ob1 handler:', args.join(' ')); }); var ob2 = new Observer(function() { //注册一个观察者 var args = Array.prototype.slice.call(arguments); console.log('ob2 handler:', args.join(' ')); }); //观察者订阅 subject.register(ob1); subject.register(ob2); //触发事件 subject.notify('hello', 'world'); subject.remove(ob1); //再次触发事件 subject.notify('hello', 'world');
可以看到,观察者模式中,观察者并不能订阅指定的事件,目标对象也不能通过触发不同事件来通知观察者。
2、发布订阅者模式
发布订阅者模式是观察者模式的变种,在这种设计模式中,订阅者 observers 可以订阅不同的事件,发布者 subject 对象也可以通过触发不同的事件来通知不同的订阅者,订阅者再执行相应的业务逻辑。
//发布者构造函数 function Subject() { this.eventSet = {}; } //订阅方法 Subject.prototype.subscribe = function(event, observer) { if (!observer || !observer.handler) { return; } if (!this.eventSet[event]) { this.eventSet[event] = []; } //在发布者的该事件数组中添加这个订阅者 this.eventSet[event].push(observer); } //取消订阅方法 Subject.prototype.remove = function(event, observer) { if (!event || !this.eventSet[event]) { return; } if (!observer) { this.eventSet[event] = []; delete this.eventSet[event]; } else { //在发布者的该事件数组中移除这个订阅者 var observers = this.eventSet[event]; var index = observers.indexOf(observer); observers.splice(index, 1); } } //触发事件 Subject.prototype.notify = function(event) { if (!event || !this.eventSet[event]) { return; } var args = Array.prototype.slice.call(arguments, 1); //找到指定的事件数组 var observers = this.eventSet[event]; //触发这个事件数组中的所有订阅者的 handler 即业务逻辑函数 observers.forEach(observer => { observer.handler && observer.handler.apply(observer, args); }) } //订阅者构造函数 function Observer(handlerfn) { this.handler = handlerfn; } //使用示例: //注册一个发布者 var sb = new Subject(); var ob1 = new Observer(function() { //注册一个订阅者 var args = Array.prototype.slice.call(arguments); console.log('ob1 handler:', args.join(' ')); }); var ob2 = new Observer(function() { //注册一个订阅者 var args = Array.prototype.slice.call(arguments); console.log('ob2 handler:', args.join(' ')); }); //订阅指定事件 sb.subscribe('js', ob1); sb.subscribe('java', ob2); //触发指定事件 sb.notify('js', 'hello', 'javascript'); //输出 ob1 handler: hello javascript //触发指定事件 sb.notify('java', 'hello', 'java'); //输出 ob2 handler: hello java sb.remove('js', ob1); //再次触发事件 sb.notify('js', 'hello', 'javascript'); sb.notify('java', 'hello', 'java'); //输出 ob2 handler: hello java
可以看到,在发布订阅者模式中,订阅者可以订阅不同的事件,发布者也可以通过触发指定的事件来通知不同的订阅者,订阅者再执行自己相应的业务逻辑。