资讯专栏INFORMATION COLUMN

js设计模式--发布订阅模式

_ang / 563人阅读

摘要:文章系列设计模式单例模式设计模式策略模式设计模式代理模式设计模式迭代器模式概念发布订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

前言

本系列文章主要根据《JavaScript设计模式与开发实践》整理而来,其中会加入了一些自己的思考。希望对大家有所帮助。

文章系列

js设计模式--单例模式

js设计模式--策略模式

js设计模式--代理模式

js设计模式--迭代器模式

概念

发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知。

场景 DOM事件
  document.body.addEventListener("click", function () {
    alert(2);
  }, false);
  document.body.addEventListener("click", function () {
    alert(3);
  }, false);
  document.body.addEventListener("click", function () {
    alert(4);
  }, false);

  document.body.click(); // 模拟用户点击
优缺点

优点:发布—订阅模式的优点非常明显,一为时间上的解耦,二为对象之间的解耦。
缺点:创建订阅者本身要消耗一定的时间和内存,而 且当你订阅一个消息后,也许此消息最后都未发生,但这个订阅者会始终存在于内存中。

例子 销售处订阅房源 简单的发布订阅
var Event = function() {
  this.list = []
}

Event.prototype.add = function(listener) {
  this.list.push(listener)
}

Event.prototype.triggle = function() {
  this.list.forEach(listener => {
    listener()
  })
}

var event = new Event()
event.add(()=>{console.log("房源1--80平--200万")})
event.add(()=>{console.log("房源2--200平--1000万")})

event.triggle()

或者

var event = {
  list: [],
  add(listener) {
    this.list.push(listener)
  },
  triggle() {
    this.list.forEach(listener => {
      listener()
    })
  }
}

event.add(()=>{console.log("房源1--80平--200万")})
event.add(()=>{console.log("房源2--200平--1000万")})

event.triggle()

但这种不能区分是发不了什么消息,比如有两群人:订阅80平房源报价和订阅200瓶房源报价的人,这里两群人都会得到通知

改进
var event = {
  list: {},
  add(type, listener) {
    if (!this.list[type]) {
      this.list[type] = []
    }
    this.list[type].push(listener)
  },
  triggle(type) {
    this.list[type] && this.list[type].forEach(listener => {
      listener()
    })
  }
}

event.add("80平", ()=>{console.log("房源1--80平--200万")})
event.add("80平", ()=>{console.log("房源2--80平--300万")})
event.add("200平", ()=>{console.log("房源2--200平--1000万")})

event.triggle("80平")

这里还少了一个取消订阅的功能

增加取消订阅
var event = {
  list: {},
  add(type, listener) {
    if (!this.list[type]) {
      this.list[type] = []
    }
    this.list[type].push(listener)
  },
  triggle(type) {
    this.list[type] && this.list[type].forEach(listener => {
      listener()
    })
  },
  remove(type, fn) {
    if (!this.list[type]) return
    var index = this.list[type].findIndex(listener => listener === fn)
    this.list[type].splice(index, 1)
  }
}

var f1 = ()=>{console.log("房源1--80平--200万")}
var f2 = ()=>{console.log("房源2--80平--300万")}
var f3 = ()=>{console.log("房源2--200平--1000万")}

event.add("80平", f1)
event.add("80平", f2)
event.add("200平", f3)

event.remove("80平", f2)
event.triggle("80平") // 房源1--80平--200万

上面代码结构还不是很清晰,我们再模拟销售部真实的场景

更真实的销售部场景

销售部

销售部有很多房源,如80平的,100平的等

客户可以到销售部登记自己想买的房源面积,并留下姓名。到时候如果有房源,销售部就会通知客户

客户由于一些原因决定不买房的时候,可以取消订阅

客户

当有房源时,客户有一个接听报价的方法

var Event = function () {
  this.list = {}
}

Event.prototype.add = function (area, client) {
  if (!this.list[area]) this.list[area] = []
  this.list[area].push(client)
}

Event.prototype.remove = function (area, client) {
  if (!this.list[area]) return
  var index = this.list[area].findIndex(item => item === client)
  this.list[area].splice(index, 1)
}


Event.prototype.triggle = function (area, price) {
  if (!this.list[area]) return
  this.list[area].forEach(client => {
    client.listen(area, price)
  })
}

var Client = function (name) {
  this.name = name
}

Client.prototype.listen = function (area, price) {
  console.log(`${this.name}收到${area}平的房源报价${price}`)
}


var client1 = new Client("client1")
var client2 = new Client("client2")


var event = new Event()
event.add("80平", client1)
event.add("100平", client1)
event.add("80平", client2)
event.add("300平", client1)
event.remove("300平", client1)

event.triggle("80平", 200) // client1收到80平平的房源报价200 client2收到80平平的房源报价200
event.triggle("100平", 500) // client1收到100平平的房源报价500
event.triggle("200平", 1000) //
event.triggle("300平", 1000) //

上面的代码虽然已经很好了,但是还是有一个缺点:订阅者接收不到订阅之前发布的消息,如下客户3也想订阅80平的房源,但他收不到任何消息

var client3 = new Client("client3")
event.add("80平", client3)

我们希望客户3也能收到消息

必须先订阅再发布吗

我们增加一个cache字段来记录历史房源报价

var Event = function () {
  this.list = {}
  this.cache = {}
}

Event.prototype.add = function (area, client) {
  if (!this.list[area]) this.list[area] = []
  this.list[area].push(client)
  this.cache[area].forEach(price => {
    client.listen(area, price)
  })
}

Event.prototype.remove = function (area, client) {
  if (!this.list[area]) return
  var index = this.list[area].findIndex(item => item === client)
  this.list[area].splice(index, 1)
}


Event.prototype.triggle = function (area, price) {
  if (!this.cache[area]) this.cache[area] = []
  this.cache[area].push(price)

  if (!this.list[area]) return
  this.list[area].forEach(client => {
    client.listen(area, price)
  })
}

var Client = function (name) {
  this.name = name
}

Client.prototype.listen = function (area, price) {
  console.log(`${this.name}收到${area}平的房源报价${price}`)
}


var client1 = new Client("client1")
var client2 = new Client("client2")


var event = new Event()
// event.add("80平", client1)
// event.add("100平", client1)
// event.add("80平", client2)
// event.add("300平", client1)
// event.remove("300平", client1)

event.triggle("80平", 200) // client1收到80平平的房源报价200 client2收到80平平的房源报价200
event.triggle("100平", 500) // client1收到100平平的房源报价500
event.triggle("200平", 1000) //
event.triggle("300平", 1000) //

var client3 = new Client("client3")
event.add("80平", client3)
event.add("100平", client3)
网站登录

假如我们正在开发一个商城网站,网站里有 header 头部、nav 导航、消息列表、购物车等模块。这几个模块的渲染有一个共同的前提条件,就是必须先用 ajax 异步请求获取用户的登录信息。

这里留给读者自己实现

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100692.html

相关文章

  • 10分钟弄懂一种简单的js设计模式(观察者/发布订阅

    摘要:发布者注册发布订阅者自动打印消息消息观察者模式与发布订阅模式类似。在此种模式中,一个目标物件在它本身的状态改变时主动发出通知,观察者收到通知从而使他们的状态自动发生变化。 做为非科班出身的前端er,每次听到设计模式都感觉很高大上,总感觉这些东西是造火箭原子弹用的,距离我们这些造螺丝钉很遥远。但是最近在做一个聊天消息的业务时,发现貌似用上发布订阅模式业务就很清晰了。创建一个消息类当作发布...

    xiguadada 评论0 收藏0
  • JS每日一题:设计模式-如何理解观察者(发布订阅)模式?

    摘要:期设计模式如何理解观察者发布订阅模式定义观察者模式又叫发布订阅模式,它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己生活实例理解你今天去看一个 20190411期 设计模式-如何理解观察者(发布订阅)模式? 定义: 观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一...

    baishancloud 评论0 收藏0
  • 观察者模式发布订阅模式JS

    摘要:最近被人问到设计模式,观察者模式和发布订阅模式二者有什么区别。观察者模式观察者模式,目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。 最近被人问到设计模式,观察者(Observer)模式和发布(Publish)/订阅(Subscribe)模式二者有什么区别。其实这两种模式还是有些许差异的,本质上的区别是调度的方式不同。 观察者模式 观察者模式,目标和观察者是基类...

    Sanchi 评论0 收藏0
  • js中的一对多 - 订阅发布模式

    摘要:解决命名空间问题暂不管,删除订阅问题这个用处不大目前我们先着手解决这个问题对应的消息么有被人订阅没有传入具体的回调函数表示取消对应的所有订阅反向遍历删除订阅回调函数这个对象,能够解决大部分事件模拟的问题。 订阅发布模式如果按数学翻译其实就是.一对多的映射关系.怎么解释呢? 就是一个开关,同时并联几个灯泡(在不同房间),触发的时候,几个灯泡都会得到指令,然后执行发光的行为。 订阅发布模式...

    Cobub 评论0 收藏0
  • JS设计模式之Obeserver(观察者)模式、Publish/Subscribe(发布/订阅模式

    摘要:观察者模式定义设计模式中对的定义一个对象称为维持一系列依赖于它观察者的对象,将有关状态的任何变更自动通知给它们。如图模式比较观察者模式则多了一个类似于话题调度中心的流程,发布者和订阅者解耦。 Obeserver(观察者)模式 定义 《js设计模式》中对Observer的定义:一个对象(称为subject)维持一系列依赖于它(观察者)的对象,将有关状态的任何变更自动通知给它们。 《设计模...

    荆兆峰 评论0 收藏0
  • 简单理解观察者模式(pub/sub)在前端中的应用

    摘要:概念观察者模式被广泛地应用于客户端编程中。所有的浏览器事件,等都是使用观察者模式的例子。在观察者模式中,一个对象订阅另一个对象的指定活动并得到通知,而不是调用另一个对象的方法。此外,观察者模式还可用于实现数据绑定。 概念 观察者模式被广泛地应用于JavaScript客户端编程中。所有的浏览器事件(mouseover,keypress等)都是使用观察者模式的例子。这种模式的另一个名字叫自...

    guyan0319 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<