精华内容
下载资源
问答
  • 发布订阅模式
    千次阅读
    2022-01-26 17:05:53

    发布/订阅模式

    什么是发布订阅模式?

    此模式分为发布者和订阅者两个概念,发布者收集订阅者的需求,然后在某个时刻告知订阅者

    例子:

    小王去小卖部买充电器,小李去小卖部买剃须刀,但是充电器和剃须刀都卖完了,于是他们在小卖部老板那儿进行了登记,等到货了老板就通知他们。

    解析:
    此案例中,小王和小李就是订阅者,小卖部老板就是发布者,等到货了之后老板就会给在他这儿登记过的人发送特定的消息

    怎么一步一步实现发布订阅模式?

    发布者

    1. 首先定义发布者
    class Dep {}
    
    1. 因为是一个收集的过程,所以可以定义一个数组,每收集一个信息就保存到数组中,由此可以再定义一个方法将收集到的信息放进数组中
    class Dep {
      constructor() {
        this.subList = [];
      }
      addSub(sub) {
        this.subList.push(sub);
      }
    }
    
    1. 发布者在特定时刻会将所有收集到的信息进行发布,所以可以定义一个发布的方法,将 subList 中的所有订阅者信息进行发布
    class Dep {
      constructor() {
        this.subList = [];
      }
      addSub(sub) {
        this.subList.push(sub);
      }
      notify() {
        this.subList.forEach(sub => sub.callPhone());
      }
    }
    
    1. 实例化发布者
    const laoban = new Dep();
    

    订阅者

    1. 首先定义发布者
    class Watcher {}
    
    1. 订阅者在发布者那里需要传递一个方法,来告知发布者到时传递给他什么,比如小王需要登记让老板告诉他充电器到货了,这里我们可以定义一个回调到订阅者里面,然后发布者发布的时候将此回调进行调用就行
    class Watcher {
      constructor(cb) {
        this.cb = cb;
      }
      callPhone() {
        this.cb();
      }
    }
    
    1. 实例化订阅者
    const xiaowang = new Watcher(() => {
      console.log("充电器到货了");
    });
    const xiaoli = new Watcher(() => {
      console.log("剃须刀到货了");
    });
    

    将订阅者添加进发布者中,然后在某个特定时机统一执行

    console.log("小王来买充电器,充电器没货了,进行了登记");
    laoban.addSub(xiaowang);
    console.log("小李来买剃须刀,剃须刀没货了,进行了登记");
    laoban.addSub(xiaoli);
    
    setTimeout(() => {
      // 到货了
      console.log("两天后到货了");
      laoban.notify();
    }, 2000);
    

    全部代码

    class Dep {
      constructor() {
        this.subList = [];
      }
      addSub(sub) {
        this.subList.push(sub);
      }
      notify() {
        this.subList.forEach(sub => sub.callPhone());
      }
    }
    
    class Watcher {
      constructor(cb) {
        this.cb = cb;
      }
      callPhone() {
        this.cb();
      }
    }
    
    const xiaowang = new Watcher(() => {
      console.log("充电器到货了");
    });
    const xiaoli = new Watcher(() => {
      console.log("剃须刀到货了");
    });
    
    const laoban = new Dep();
    
    console.log("小王来买充电器,充电器没货了,进行了登记");
    laoban.addSub(xiaowang);
    console.log("小李来买剃须刀,剃须刀没货了,进行了登记");
    laoban.addSub(xiaoli);
    setTimeout(() => {
      // 到货了
      console.log("两天后到货了");
      laoban.notify();
    }, 2000);
    

    总结: 一个很常见的设计模式,在 vue 的双向数据绑定中有用到,代码很少,可以阅读一下

    更多相关内容
  • 主要介绍了JavaScript设计模式之观察者模式(发布订阅模式)原理与实现方法,结合实例形式分析了JavaScript观察者模式概念、原理、使用方法及相关操作注意事项,需要的朋友可以参考下
  • 本文实例讲述了JavaScript设计模式之观察者模式与发布订阅模式。分享给大家供大家参考,具体如下: 学习了一段时间设计模式,当学到观察者模式和发布订阅模式的时候遇到了很大的问题,这两个模式有点类似,有点傻傻...
  • 该资源是C#不同窗体间的数据传递发布订阅模式(观察者模式)源码范例,资源很好,思路清晰,值得大家借鉴
  • 主要介绍了Vue发布订阅模式实现过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • JavaScript设计模式:四、发布订阅模式 文章目录JavaScript设计模式:四、发布订阅模式一、概述1. 观察者模式2. 发布订阅模式3. 观察者模式是不是发布订阅模式 一、概述 观察者模式: 观察者(Observer)直接订阅...

    JavaScript设计模式:四、发布订阅模式

    一、概述

    观察者模式: 观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。

    发布订阅模式: 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
    在这里插入图片描述

    1. 观察者模式

    1. 首先定义一个数组存储订阅列表(数组存函数)
    2. 定义订阅函数,函数参数:订阅对象与订阅信息。函数体负责将订阅信息(为一个函数)存入订阅数组列表。
    3. 定义发布任务函数,函数接受订阅信息参数。函数体内遍历订阅信息,以遍能够找到匹配的订阅信息。

    主要维护一个存储函数的数组,通过入栈的方式维护订阅信息,通过数组遍历的方式使用订阅列表,以找到匹配的订阅信息。

    function Hunter(name, level) {
      this.name = name;
      this.level = level;
      this.list = [];
    }
    Hunter.prototype.publish = function(money) {
      console.log(this.level + '猎人' + this.name + '寻求帮助');
      this.list.forEach(function(item, index) {
        item(money);
      })
    }
    Hunter.prototype.subscribe = function(target, fn) {
      console.log(this.level + '猎人' + this.name + '订阅了' + target);
      target.list.push(fn); // 向目标猎人list中推入订阅
    }
    let hounterMing = new Hunter('小明','黄金');
    let hounterJin = new Hunter('小金','黄金');
    let hounterZhang = new Hunter('校长', '黄金');
    let hounterPeter = new Hunter('Peter', '黄铜');
    
    hunterMing.subscribe(hunterPeter, function(money){
      console.log('小明表示:' + (money > 200 ? '' : '暂时很忙,不能') + '给予帮助')
    })
    hunterJin.subscribe(hunterPeter, function(){
      console.log('小金表示:给予帮助')
    })
    hunterZhang.subscribe(hunterPeter, function(){
      console.log('小金表示:给予帮助')
    })
    hunterPeter.publish(198)
    

    2. 发布订阅模式

    观察者模式和发布订阅模式最大的区别就是发布订阅模式有个事件调度中心。

    观察者模式由具体目标调度,每个被订阅的目标里面都需要有对观察者的处理,这种处理方式比较直接粗暴,但是会造成代码的冗余。

    而发布订阅模式中统一由调度中心进行处理,订阅者和发布者互不干扰,消除了发布者和订阅者之间的依赖。这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。

    通俗版本:

    1. 发布订阅模式就是将原本属于被订阅者维护的订阅列表独立出来,增加了一个专门处理订阅信息的订阅中心。实际上依然是维护一个数组列表。
    2. 发布者和订阅者的发布和订阅的具体内部逻辑被订阅中心接管,只需要调用订阅中心的函数即可。
    /**
     * HunterUnion 负责任务函数的存储,实现形式为对象数组的入栈和遍历。
     * 内部数据结构为 :
     * topics: {
     *   'tiger1': [functionA(), functionB, function C],
     *   'tiger2': [functionA(), functionB, function C],
     * }
     */
    let HunterUnion = {
      type: 'hunt',
      topics: Object.create(null),
      subscribe: function (topic, fn){
          if(!this.topics[topic]){
              this.topics[topic] = [];  
          }
          this.topics[topic].push(fn);
      },
      publish: function (topic, money){
          if(!this.topics[topic])
              return;
          for(let fn of this.topics[topic]){
            fn(money)
          }
      }
    }
    
    // Hunter只负责存储基本的订阅信息
    function Hunter(name, level) {
      this.name = name;
      this.level = level;
    }
    
    Hunter.prototype.subscribe = function(topic, fn) {
      console.log(this.level + '猎人' + 
        this.name + '订阅了狩猎' + topic + '的任务');
      HunterUnion.subscribe(topic, fn);
    }
    Hunter.prototype.publish = function(topic, money) {
      console.log(this.level + '猎人' + 
        this.name + '发布了狩猎' + topic + '的任务');
        HunterUnion.publish(topic, money);
    }
    
    //猎人工会走来了几个猎人
    let hunterMing = new Hunter('小明', '黄金')
    let hunterJin = new Hunter('小金', '白银')
    let hunterZhang = new Hunter('小张', '黄金')
    let hunterPeter = new Hunter('Peter', '青铜')
    
    hunterMing.subscribe('tiger', function(money){
      console.log('小明表示:' + (money > 200 ? '' : '不') + '接取任务')
    })
    hunterJin.subscribe('tiger', function(money){
      console.log('小金表示:接取任务')
    })
    hunterZhang.subscribe('tiger', function(money){
      console.log('小张表示:接取任务')
    })
    //Peter订阅了狩猎sheep的任务
    hunterPeter.subscribe('sheep', function(money){
      console.log('Peter表示:接取任务')
    })
    
    //Peter发布了狩猎tiger的任务
    hunterPeter.publish('tiger', 198)
    

    3. 观察者模式是不是发布订阅模式

    网上关于这个问题的回答,出现了两极分化,有认为发布订阅模式就是观察者模式的,也有认为观察者模式和发布订阅模式是真不一样的。

    其实我不知道发布订阅模式是不是观察者模式,就像我不知道辨别模式的关键是设计意图还是设计结构(理念),虽然《JavaScript设计模式与开发实践》一书中说了分辨模式的关键是意图而不是结构。

    如果以结构来分辨模式,发布订阅模式相比观察者模式多了一个中间件订阅器,所以发布订阅模式是不同于观察者模式的;如果以意图来分辨模式,他们都是实现了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新,那么他们就是同一种模式,发布订阅模式是在观察者模式的基础上做的优化升级。

    不过,不管他们是不是同一个设计模式,他们的实现方式确实有差别,我们在使用的时候应该根据场景来判断选择哪个。

    展开全文
  • 深入Vue原理_全面剖析发布订阅模式

    千次阅读 多人点赞 2022-04-01 11:07:05
    文章目录发布订阅模式优化优化思路思考理解发布订阅模式(自定义事件)收集更新函数触发更新函数6.5 总结总结写在最后 上节中我们提到下方更新的问题:无法做到精准更新 <div id="app"> <p v-text="name"&...

    欢迎各位小伙伴们!
    为大家推荐一款刷题神奇哦 点击链接访问牛客网
    各大互联网大厂面试真题。从基础到入阶乃至原理刨析类面试题 应有尽有,赶快来装备自己吧!助你面试稳操胜券,solo全场面试官
    上节中我们提到下方更新的问题:无法做到精准更新

    <div id="app">
      <p v-text="name"></p>
      <p v-text="age"></p>
      <p v-text="name"></p>
    </div>
    <script>
      let data = {
        name: '小兰同学',
        age: 18,
        height: 180
      }
      // 遍历每一个属性
      Object.keys(data).forEach((key) => {
        // key 属性名
        // data[key] 属性值
        // data 原对象
        defineReactive(data, key, data[key])
      })
      function defineReactive(data, key, value) {
        Object.defineProperty(data, key, {
          get() {
            return value
          },
          set(newVal) {
            // 数据发生变化,操作dom进行更新
            if (newVal === value) {
              return
            }
            value = newVal
            compile()
          }
        })
      }
      // 编译函数
      function compile() {
        let app = document.getElementById('app')
        // 1.拿到app下所有的子元素
        const nodes = app.childNodes   //  [text, input, text]
        //2.遍历所有的子元素
        nodes.forEach(node => {
          // nodeType为1为元素节点
          if (node.nodeType === 1) {
            const attrs = node.attributes
            Array.from(attrs).forEach(attr => {
              const dirName = attr.nodeName
              const dataProp = attr.nodeValue
              console.log( dirName,dataProp)
              if (dirName === 'v-text') {
                console.log(`更新了${dirName}指令,需要更新的属性为${dataProp}`)
                node.innerText = data[dataProp]
              }
            })
          }
        })
      }
      // 首次渲染
      compile()
    </script>
    

    发布订阅模式优化

    优化思路思考

    1.数据更新之后实际上需要执行的代码是什么?

    node.innerText = data[dataProp]
    

    为了保存当前的node和dataProp,我们再次设计一个函数执行利用闭包函数将每一次编译函数执行时候的node和dataProp都缓存下来,所以每一次数据变化之后执行的是这样的一个更新函数

    () => {
      node.innerText = data[dataProp]
    }
    

    2.一个响应式数据可能会有多个视图部分都需要依赖,也就是响应式数据变化之后,需要执行的更新函数可能不止一个,如下面的代码所示,name属性有俩个div元素都使用了它,所以当name变化之后,俩个div节点都需要得到更新,那属性和更新函数之间应该是一个一对多的关系

    <div id="app">
       <div v-text="name"></div>
       <div v-text="name"></div>
       <p v-text="age"></p>
       <p v-text="age"></p>
    </div>
    
    <script>
      let data = {
         name: 'cp',
         age: 18
      }
    </script>
    

    经过分析我们可以得到下面的存储架构图,每一个响应式属性都绑定了相对应的更新函数,是一个一对多的关系,数据发生变化之后,只会再次执行和自己绑定的更新函数

    在这里插入图片描述

    理解发布订阅模式(自定义事件)

    理解发布订阅,关键是理解一对多

    1. 从浏览器事件说起

    dom绑定事件的方式,我们学过俩种

    1. dom.onclick = function(){}
    2. dom.addEventListener(‘click’,()=>{})

    这俩种绑定方式的区别是,第二种方案可以实现同一个事件绑定多个回调函数,很明显这是一个一对多的场景,既然浏览器也叫作事件,我们试着分析下浏览器事件绑定实现的思路

    1. 首先addEventListenr是一个函数方法,接受俩个参数,分别是事件类型回调函数

    2. 因为是一个事件绑定多个回调函数,那在内存里大概会有这样的一个数据结构

      {
        click: ['cb1','cb2',....],
        input: ['cb1','cb2',...]
      }
      
    3. 触发事件执行,浏览器因为有鼠标键盘输入可以触发事件,大概的思路是通过事件名称找到与之关联的回调函数列表,然后遍历执行一遍即可

    ok,我们分析了浏览器事件的底层实现思路,那我们完全可以自己模仿一个出来,事件的触发,我们也通过设计一个方法来执行

    2. 实现简单的发布订阅

    // 增加dep对象 用来收集依赖和触发依赖
    const dep = {
        map: Object.create(null),
        // 收集
        collect(dataProp, updateFn) {
          if (!this.map[dataProp]) {
            this.map[dataProp] = []
          }
          this.map[dataProp].push(updateFn)
        },
        // 触发
        trigger(dataProp) {
          this.map[dataProp] && this.map[dataProp].forEach(updateFn => {
            updateFn()
          })
        }
    }
    

    收集更新函数

    在编译函数执行的时候,我们把用于更新dom的更新函数收集起来

     // 编译函数
      function compile() {
        let app = document.getElementById('app')
        // 1.拿到app下所有的子元素
        const nodes = app.childNodes   //  [text, input, text]
        //2.遍历所有的子元素
        nodes.forEach(node => {
          // nodeType为1为元素节点
          if (node.nodeType === 1) {
            const attrs = node.attributes
            // 遍历所有的attrubites找到 v-model
            Array.from(attrs).forEach(attr => {
              const dirName = attr.nodeName
              const dataProp = attr.nodeValue
              console.log(dirName, dataProp)
              if (dirName === 'v-text') {
                console.log(`更新了${dirName}指令,需要更新的属性为${dataProp}`)
                node.innerText = data[dataProp]
                // 收集更新函数
                dep.collect(dataProp, () => {
                  node.innerText = data[dataProp]
                })
              }
            })
          }
        })
     }
    

    触发更新函数

    当属性发生变化的时候,我们通过属性找到对应的更新函数列表,然后依次执行即可

    function defineReactive(data, key, value) {
        Object.defineProperty(data, key, {
          get() {
            return value
          },
          set(newValue) {
            // 更新视图
            if (newValue === value) return
            value = newValue
            // 再次编译要放到新值已经变化之后只更新当前的key
            dep.trigger(key)
          }
        })
    }
    

    6.5 总结

    1. 了解了发布订阅模式的基础形态
    2. 了解发布订阅可以解决什么样的具体问题(精准更新)

    总结

    1. 数据响应式的实现无非是对象属性拦截,我们使用Object.defineProperty来实现,在vue3中使用Proxy对象代理方案进行了优化,解决了Object.defineProperty存在的缺陷

    2. observe对象指的是把数据处理成响应式的对象

      watcher指的其实就是数据变化之后的更新函数 (Vue中的watcher有两种,一种是用来更新视图的watcher,一种是通过watch配置项声明的watcher)

      dep指的就是使用发布订阅实现的收集更新函数和触发更新函数的对象

    3. 指令实现的核心无非是通过模板编译找到标识然后把数据绑上去,等到数据变化之后再重新放一次

    4. 发布订阅模式的本质是解决一对多的问题,在vue中实现数据变化之后的精准更新

    写在最后

    原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 \textcolor{blue}{原创不易,还希望各位大佬支持一下}

    👍 点 赞 , 你 的 认 可 是 我 创 作 的 动 力 ! \textcolor{green}{点赞,你的认可是我创作的动力!}

    ⭐️ 收 藏 , 你 的 青 睐 是 我 努 力 的 方 向 ! \textcolor{green}{收藏,你的青睐是我努力的方向!}

    ✏️ 评 论 , 你 的 意 见 是 我 进 步 的 财 富 ! \textcolor{green}{评论,你的意见是我进步的财富!}

    本期推荐

    在这里插入图片描述

    【内容简介】
      本书以理论结合编程开发为原则,使用Python作为开发语言,讲解化算法的原理和应用,详细介绍了Python基础、Gurobi 优化器、线性规划、整数规划、多目标优化、动态规划、图与网络分析、智能优化算法。对于算法部分的每一种算法都包含原理和编程实践,使读者对化算法的认识更加深入。
     
      本书分为 3 篇共 9 章。第 1 篇(第 1~3 章)是化算法与编程基础:第 1 章介绍了什么是化算法及其在生产和生活中的应用;第 2章介绍Python编程基础和Python数据分析库及绘图库;第 3章讲解Gurobi 优化器的基础和高级特性。第 2篇(第 4~6章)是数学规划方法:第 4章详细讲解线性规划的知识,包括单纯形法、内点法、列生成法、拉格朗日乘子法、对偶问题;第 5 章讲解整数规划解法的分支定界法和割平面法;第 6 章讲解多目标优化的概念及基于单纯形法的目标规划法。第 3 篇(第 7~9 章)是启发式算法:第 7 章介绍动态规划算法;第 8 章讲解图与网络分析,介绍*小生成树、短路径、网络流、路径规划等问题的建模;第 9 章讲解了粒子群算法和遗传算法求解各种类型优化算法问题的方法。
      本书内容丰富,实例典型,实用性强,适合各个层次从事
    化算法研究和应用的人员,尤其适合有一定算法基础而没有编程基础的人员阅读。

    【作者简介】
      苏振裕,厦门大学金融学硕士,现任SHEIN 智慧供应链资深算法工程师。知乎专栏《从推公式到写代码》作者,运筹优化论坛(optimize.fun)创建人。在大数据、人工智能、运筹优化和供应链方面,具有多年的相关算法研究应用经验。

    展开全文
  • 发布订阅模式与观察者模式

    万次阅读 多人点赞 2019-03-29 18:25:12
    设计模式并非是软件开发的专业术语,实际上,“模式”最早诞生于建筑学。 设计模式的定义是:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。通俗一点说,设计模式是在某种场合下对某个问题的一种...

    背景

    设计模式并非是软件开发的专业术语,实际上,“模式”最早诞生于建筑学。

    设计模式的定义是:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。通俗一点说,设计模式是在某种场合下对某个问题的一种解决方案。如果再通俗一点说,设计模式就是给面向对象软件开发中的一些好的设计取个名字。

    这些“好的设计”并不是谁发明的,而是早已存在于软件开发中。一个稍有经验的程序员也许在不知不觉中数次使用过这些设计模式。GoF(Gang of Four–四人组,《设计模式》几位作者)最大的功绩是把这些“好的设计”从浩瀚的面向对象世界中挑选出来,并且给予它们一个好听又好记的名字。

    设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案,他不是一个死的机制,他是一种思想,一种写代码的形式。每种语言对于各种设计模式都有他们自己的实现方式,对于某些设计模式来说,可能在某些语言下并不适用,比如工厂方法模式对于javascript。模式应该用在正确的地方。而哪些才算正确的地方,只有在我们深刻理解了模式的意图之后,再结合项目的实际场景才会知道。。

    模式的社区一直在发展。GoF在1995年提出了23种设计模式,但模式不仅仅局限于这23种,后面增加到了24种。在这20多年的时间里,也许有更多的模式已经被人发现并总结了出来,比如一些JavaScript 图书中会提到模块模式、沙箱模式等。这些“模式”能否被世人公认并流传下来,还有待时间验证。

    观察者模式(Observer Pattern)

    观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。

    观察者模式有一个别名叫“发布-订阅模式”,或者说是“订阅-发布模式”,订阅者和订阅目标是联系在一起的,当订阅目标发生改变时,逐个通知订阅者。我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸,报社和订报纸的客户就是上面文章开头所说的“一对多”的依赖关系。

    发布订阅模式(Pub-Sub Pattern)

    其实24种基本的设计模式中并没有发布订阅模式,上面也说了,他只是观察者模式的一个别称。

    但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。

    在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。

    举一个例子,你在微博上关注了A,同时其他很多人也关注了A,那么当A发布动态的时候,微博就会为你们推送这条动态。A就是发布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往来的,全是通过微博来协调的(你的关注,A的发布动态)。

    观察者模式和发布订阅模式有什么区别?

    我们先来看下这两个模式的实现结构:
    模式结构

    观察者模式: 观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。

    发布订阅模式: 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

    我们再来看下这两个模式的代码案例:(猎人发布与订阅任务)

    观察者模式:

        //有一家猎人工会,其中每个猎人都具有发布任务(publish),订阅任务(subscribe)的功能
    	//他们都有一个订阅列表来记录谁订阅了自己
    	//定义一个猎人类
    	//包括姓名,级别,订阅列表
    	function Hunter(name, level){
    		this.name = name
    		this.level = level
    		this.list = []
    	}
    	Hunter.prototype.publish = function (money){
    		console.log(this.level + '猎人' + this.name + '寻求帮助')
    	    this.list.forEach(function(item, index){
    	    	item(money)
    	    })
    	}
    	Hunter.prototype.subscribe = function (targrt, fn){
    		console.log(this.level + '猎人' + this.name + '订阅了' + targrt.name)
    	    targrt.list.push(fn)
    	}
    	
    	//猎人工会走来了几个猎人
    	let hunterMing = new Hunter('小明', '黄金')
    	let hunterJin = new Hunter('小金', '白银')
    	let hunterZhang = new Hunter('小张', '黄金')
    	let hunterPeter = new Hunter('Peter', '青铜')
    	
    	//Peter等级较低,可能需要帮助,所以小明,小金,小张都订阅了Peter
    	hunterMing.subscribe(hunterPeter, function(money){
    		console.log('小明表示:' + (money > 200 ? '' : '暂时很忙,不能') + '给予帮助')
    	})
    	hunterJin.subscribe(hunterPeter, function(){
    		console.log('小金表示:给予帮助')
    	})
    	hunterZhang.subscribe(hunterPeter, function(){
    		console.log('小金表示:给予帮助')
    	})
    	
    	//Peter遇到困难,赏金198寻求帮助
    	hunterPeter.publish(198)
    	
    	//猎人们(观察者)关联他们感兴趣的猎人(目标对象),如Peter,当Peter有困难时,会自动通知给他们(观察者)
    

    发布订阅模式:

        //定义一家猎人工会
    	//主要功能包括任务发布大厅(topics),以及订阅任务(subscribe),发布任务(publish)
    	let HunterUnion = {
    		type: 'hunt',
    		topics: Object.create(null),
    		subscribe: function (topic, fn){
    		    if(!this.topics[topic]){
    		      	this.topics[topic] = [];  
    		    }
    		    this.topics[topic].push(fn);
    		},
    		publish: function (topic, money){
    		    if(!this.topics[topic])
    		      	return;
    		    for(let fn of this.topics[topic]){
    		    	fn(money)
    		    }
    		}
    	}
    	
    	//定义一个猎人类
    	//包括姓名,级别
    	function Hunter(name, level){
    		this.name = name
    		this.level = level
    	}
    	//猎人可在猎人工会发布订阅任务
    	Hunter.prototype.subscribe = function (topic, fn){
    		console.log(this.level + '猎人' + this.name + '订阅了狩猎' + topic + '的任务')
    	    HunterUnion.subscribe(topic, fn)
    	}
    	Hunter.prototype.publish = function (topic, money){
    		console.log(this.level + '猎人' + this.name + '发布了狩猎' + topic + '的任务')
    	    HunterUnion.publish(topic, money)
    	}
    	
    	//猎人工会走来了几个猎人
    	let hunterMing = new Hunter('小明', '黄金')
    	let hunterJin = new Hunter('小金', '白银')
    	let hunterZhang = new Hunter('小张', '黄金')
    	let hunterPeter = new Hunter('Peter', '青铜')
    	
    	//小明,小金,小张分别订阅了狩猎tiger的任务
    	hunterMing.subscribe('tiger', function(money){
    		console.log('小明表示:' + (money > 200 ? '' : '不') + '接取任务')
    	})
    	hunterJin.subscribe('tiger', function(money){
    		console.log('小金表示:接取任务')
    	})
    	hunterZhang.subscribe('tiger', function(money){
    		console.log('小张表示:接取任务')
    	})
    	//Peter订阅了狩猎sheep的任务
    	hunterPeter.subscribe('sheep', function(money){
    		console.log('Peter表示:接取任务')
    	})
    	
    	//Peter发布了狩猎tiger的任务
    	hunterPeter.publish('tiger', 198)
    	
    	//猎人们发布(发布者)或订阅(观察者/订阅者)任务都是通过猎人工会(调度中心)关联起来的,他们没有直接的交流。
    

    观察者模式和发布订阅模式最大的区别就是发布订阅模式有个事件调度中心。

    观察者模式由具体目标调度,每个被订阅的目标里面都需要有对观察者的处理,这种处理方式比较直接粗暴,但是会造成代码的冗余。

    而发布订阅模式中统一由调度中心进行处理,订阅者和发布者互不干扰,消除了发布者和订阅者之间的依赖。这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。

    观察者模式是不是发布订阅模式

    网上关于这个问题的回答,出现了两极分化,有认为发布订阅模式就是观察者模式的,也有认为观察者模式和发布订阅模式是真不一样的。

    其实我不知道发布订阅模式是不是观察者模式,就像我不知道辨别模式的关键是设计意图还是设计结构(理念),虽然《JavaScript设计模式与开发实践》一书中说了分辨模式的关键是意图而不是结构

    如果以结构来分辨模式,发布订阅模式相比观察者模式多了一个中间件订阅器,所以发布订阅模式是不同于观察者模式的;如果以意图来分辨模式,他们都是实现了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新,那么他们就是同一种模式,发布订阅模式是在观察者模式的基础上做的优化升级。

    不过,不管他们是不是同一个设计模式,他们的实现方式确实有差别,我们在使用的时候应该根据场景来判断选择哪个。

    展开全文
  • Java实现发布订阅模式

    千次阅读 2022-01-13 00:29:23
    发布订阅模式是软件开发者很常见的一种设计模式,很多开源库都使用了发布订阅模式,例如RxJava、EventBus、Vue等,所以学习该模式还是很有必要的。 该模式中存在一个或多个发布者,一个或多个订阅者,当发布者发布...
  • RabbitMQ-Java-04-发布订阅模式

    千次阅读 2022-01-03 17:47:48
    RabbitMQ-Java-04-发布订阅模式 本案例是一个Maven项目 假设你已经实现了上一节工作队列 官方文档已包含绝大多数本案例内容。请移步:https://docs.spring.io/spring-amqp/docs/current/reference/html/ 核心概念 ...
  • vue 发布订阅模式

    千次阅读 2022-03-15 14:12:36
    vue 发布订阅模式 为什么要使用发布订阅模式 vue 中数据反映到视图中的方式主要是采取声明式渲染+模板编译 声明式渲染: 例如v-mdoe等指令的形式渲染 模板编译原理: 简单来讲就是获取app下所有的childNodes 通过...
  • 该例子程序是用C++代码编写,实现了发布-订阅模式;通过该例子可以很好的理解设计模式中的发布-订阅模式的精髓;
  • 上次研究观察者模式,很多文章说它也叫Subscribe/Publish(发布/订阅模式)。可在《Javascript设计模式》一书中,这两种模式还是有些区别的。书中原话如下: 1.Observer模式要求希望接收到主题通知者的观察者必须订阅...
  • js代码-实现发布/订阅模式
  • 浅谈JS发布订阅模式

    千次阅读 2022-06-03 18:17:20
    在使用前端各大框架时,多多少少会使用过或听说过发布订阅模式,本篇文章将使用原生实现一个简单的发布订阅模式,并演示其在中进行跨组件通信的作用简单来说其实是一种对象间一对多的依赖关系,当一个对象的状态发送...
  • 观察者模式VS发布订阅模式

    千次阅读 2022-04-03 23:42:00
    观察者模式vs发布/订阅模式很容易混淆,像是凤梨和菠萝,傻傻分不清。Observer模式通常用Publish/Subscribe模式实现,我刚开始学习js的时候,以为这是同一回事,但是仔细学习,发现它们是有质的区别的。 二、观察者...
  • Redis的发布订阅模式

    千次阅读 2021-12-14 19:52:10
    Redis发布订阅模式的总结及使用
  • 发布订阅模式-前端设计模式

    千次阅读 2022-04-26 21:51:19
    首先理解 发布订阅 利用报刊的场景 小时候,家里人有看报刊的习惯, 会和联系送报刊的人 告诉他,我需要什么类型的报刊。 - 这个可以被称为订阅 接着报刊到了,送报刊的人,会把报刊送到我家。-这属于发布 在...
  • React 中的发布订阅模式

    千次阅读 2022-02-27 12:03:01
    发布订阅模式
  • Redis发布订阅模式

    2022-05-19 22:40:25
    1.redis环境安装和配置 sudo apt-get install redis-server # ubuntu命令安装redis服务 ps -ef | grep redis ubuntu通过上面命令安装完...redis的发布-订阅机制:发布-订阅模式包含了两种角色,分别是消息的发布.
  • Vue发布订阅模式

    2022-04-23 21:41:44
    我的回答:“发布订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到状态改变的通知。具体过程就是订阅者把自己想订阅的事件注册到调度中心,当发布者发布该事件到...
  • Redis发布订阅模式实现原理

    千次阅读 2022-03-09 14:55:05
    发布订阅系统在我们日常的工作中经常会使用到,这种场景大部分情况我们都是使用消息队列,常用的消息队列有 Kafka,RocketMQ,RabbitMQ,每一种消息队列都有其特性,很多时候我们可能不需要独立部署相应的消息队列,...
  • 订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象。这篇文章主要介绍了发布订阅模式在vue中的实际运用,需要的朋友可以参考下
  • RabbitMQ 之发布订阅模式

    千次阅读 2022-04-19 18:38:31
    发布订阅模式中,生产者不再直接与队列绑定,而是将数据发送至交换机Exchange 交换机Exchange用于将数据按某种规则送入与之绑定的队列,进而供消费者使用。 发布订阅模式中,交换机将无差别的将所有消息送入与之绑定...
  • Vue 发布订阅模式

    千次阅读 2021-09-23 08:43:26
    发布订阅模式:订阅者,发布者,信号中心 我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心"发布"(publish)一个信号,其它任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己...
  • 主要介绍了浅谈发布订阅模式与观察者模式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 本文实例讲述了JavaScript事件发布/订阅模式原理与用法。分享给大家供大家参考,具体如下: 1、发布/订阅模式也是诸多设计模式当中的一种; 2、这种方式可以在es5下相当优雅地处理异步操作; 3、什么是发布/订阅呢?...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 159,182
精华内容 63,672
关键字:

发布订阅模式