1、观察者模式

观察者模型是非常普遍的一种设计模式,通常会用来在不同系统之间进行解耦。

观察者模式:两种关键对象和三种关键操作

  1. subject对象:提供三种基本操作方式:被订阅(注册监听方法 register),被取消订阅(移除监听方法 remove),触发事件(notify)
  2. 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

可以看到,在发布订阅者模式中,订阅者可以订阅不同的事件,发布者也可以通过触发指定的事件来通知不同的订阅者,订阅者再执行自己相应的业务逻辑。

 

相关文章: