zoukankan      html  css  js  c++  java
  • 观察者模式和发布订阅者模式

    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

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

  • 相关阅读:
    PHP做Web开发的MVC框架(Smarty使用说明 )
    PHP + Smarty + html5 构建Wap应用
    HTML5游戏中动画帧的概念理解
    [转]jQuery选择器 (详解)
    2014马年应该有怎么样的学习方式和思考原则
    html5视频播放解决方案
    html5学习摘要
    sqlserver2008行锁
    关于一些url中传递参数有空格问题
    MongoDB和Redis区别
  • 原文地址:https://www.cnblogs.com/wenxuehai/p/11765468.html
Copyright © 2011-2022 走看看