当前位置: 首页 > news >正文

谈谈观察者模式和发布订阅模式

在网上看到许多关于观察者模式和发布订阅模式的博文,发现很多人都认为观察者模式即发布订阅模式,经过进一步的学习和理解,我认为观察者模式和发布订阅模式还是有一些区别的,下面谈谈我对观察者模式和发布订阅模式的理解「PS:欢迎各路大神指正」。

观察者模式(Observer)

观察者模式指的是一个对象(Subject)维持一系列依赖于它的对象(Observer),当有关状态发生变更时 Subject 对象则通知一系列 Observer 对象进行更新。

在观察者模式中,Subject 对象拥有添加、删除和通知一系列 Observer 的方法等等,而 Observer 对象拥有更新方法等等。

在 Subject 对象添加了一系列 Observer 对象之后,Subject 对象则维持着这一系列 Observer 对象,当有关状态发生变更时 Subject 对象则会通知这一系列 Observer 对象进行更新。

function Subject(){
  this.observers = [];
}

Subject.prototype = {
  add:function(observer){  // 添加
    this.observers.push(observer);
  },
  remove:function(observer){  // 删除
    var observers = this.observers;
    for(var i = 0;i < observers.length;i++){
      if(observers[i] === observer){
        observers.splice(i,1);
      }
    }
  },
  notify:function(){  // 通知
    var observers = this.observers;
    for(var i = 0;i < observers.length;i++){
      observers[i].update();
    }
  }
}

function Observer(name){
  this.name = name;
}

Observer.prototype = {
  update:function(){  // 更新
    console.log('my name is '+this.name);
  }
}

var sub = new Subject();

var obs1 = new Observer('ttsy1');
var obs2 = new Observer('ttsy2');

sub.add(obs1);
sub.add(obs2);
sub.notify();  //my name is ttsy1、my name is ttsy2
复制代码

上述代码中,我们创建了 Subject 对象和两个 Observer 对象,当有关状态发生变更时则通过 Subject 对象的 notify 方法通知这两个 Observer 对象,这两个 Observer 对象通过 update 方法进行更新。

在 Subject 对象添加了一系列 Observer 对象之后,还可以通过 remove 方法移除某个 Observer 对象对它的依赖。

var sub = new Subject();

var obs1 = new Observer('ttsy1');
var obs2 = new Observer('ttsy2');

sub.add(obs1);
sub.add(obs2);
sub.remove(obs2);
sub.notify();  //my name is ttsy1
复制代码

发布订阅模式(Publisher && Subscriber)

发布订阅模式指的是希望接收通知的对象(Subscriber)基于一个主题通过自定义事件订阅主题,被激活事件的对象(Publisher)通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。

let pubSub = {
  list:{},
  subscribe:function(key,fn){  // 订阅
    if (!this.list[key]) {
      this.list[key] = [];
    }
    this.list[key].push(fn);
  },
  publish:function(){  // 发布
    let arg = arguments;
    let key = [].shift.call(arg);
    let fns = this.list[key];

    if(!fns || fns.length<=0) return false;

    for(var i=0,len=fns.length;i<len;i++){
      fns[i].apply(this, arg);
    }

  },
  unSubscribe(key) {  // 取消订阅
    delete this.list[key];
  }
};

pubSub.subscribe('name', (name) => {
  console.log('your name is ' + name);
});
pubSub.subscribe('sex', (sex) => {
  console.log('your sex is ' + sex);
});
pubSub.publish('name', 'ttsy1');  // your name is ttsy1
pubSub.publish('sex', 'male');  // your sex is male
复制代码

上述代码的订阅是基于 name 和 sex 主题来自定义事件,发布是通过 name 和 sex 主题并传入自定义事件的参数,最终触发了特定主题的自定义事件。

可以通过 unSubscribe 方法取消特定主题的订阅。

pubSub.subscribe('name', (name) => {
  console.log('your name is ' + name);
});
pubSub.subscribe('sex', (sex) => {
  console.log('your sex is ' + sex);
});
pubSub.unSubscribe('name');
pubSub.publish('name', 'ttsy1');  // 这个主题被取消订阅了
pubSub.publish('sex', 'male');  // your sex is male
复制代码

观察者模式 VS 发布订阅模式

观察者模式与发布订阅模式都是定义了一个一对多的依赖关系,当有关状态发生变更时则执行相应的更新。

不同的是,在观察者模式中依赖于 Subject 对象的一系列 Observer 对象在被通知之后只能执行同一个特定的更新方法,而在发布订阅模式中则可以基于不同的主题去执行不同的自定义事件。相对而言,发布订阅模式比观察者模式要更加灵活多变。

我认为,观察者模式和发布订阅模式本质上的思想是一样的,而发布订阅模式可以被看作是观察者模式的一个进阶版。

设计模式只是一种思想,某一种设计模式都可以有很多种不同的实现方式,各种实现都有其优劣之分,具体的实现方式需要基于不同的业务场景。上述是我对观察者模式和发布订阅模式学习之后的一些理解,望指正。

不定时分享个人在前端方面的学习经验,觉得还不错的小伙伴,可以关注一波公众号哦。

相关文章:

  • 策略模式
  • spark本地环境的搭建到运行第一个spark程序
  • VC6不支持typedef中递归。终于找到了Tuple的实现方案。
  • 设计模式-工厂模式
  • RHCS Oracle HA for OEL5.8 KVM实践配置
  • 面试必问之【对象和函数】篇
  • Hyper-v Server在线调整虚拟硬盘大小
  • Redis配置解读
  • JSP、Java、JavaScript与JScript总结
  • dict(字典)
  • Android Handler机制理解
  • 前端面试忽悠师入门,教你如何从容面试。
  • mysql用户权限设置
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • linux下去除空行的方法
  • [LeetCode] Wiggle Sort
  • Apache的基本使用
  • Centos6.8 使用rpm安装mysql5.7
  • centos安装java运行环境jdk+tomcat
  • Codepen 每日精选(2018-3-25)
  • css选择器
  • Django 博客开发教程 16 - 统计文章阅读量
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • JDK 6和JDK 7中的substring()方法
  • js操作时间(持续更新)
  • laravel5.5 视图共享数据
  • nginx 配置多 域名 + 多 https
  • node和express搭建代理服务器(源码)
  • oschina
  • redis学习笔记(三):列表、集合、有序集合
  • 复杂数据处理
  • 聊聊directory traversal attack
  • 区块链技术特点之去中心化特性
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ​一些不规范的GTID使用场景
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • $(function(){})与(function($){....})(jQuery)的区别
  • (20050108)又读《平凡的世界》
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • ***通过什么方式***网吧
  • .NET 服务 ServiceController
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • .NET命令行(CLI)常用命令
  • .NET企业级应用架构设计系列之开场白
  • .NET与 java通用的3DES加密解密方法
  • .net中调用windows performance记录性能信息
  • /etc/sudoers (root权限管理)
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [ 云计算 | AWS 实践 ] Java 如何重命名 Amazon S3 中的文件和文件夹
  • [@Controller]4 详解@ModelAttribute