-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 23 题:介绍下观察者模式和订阅-发布模式的区别,各自适用于什么场景 #25
Comments
|
可不可以理解 为 观察者模式没中间商赚差价 |
观察者模式依赖一旦改变就会触发更新,而订阅发布模式则需要手动触发更新 |
联系发布-订阅模式是观察者模式的一种变体。发布-订阅只是把一部分功能抽象成一个独立的ChangeManager。 意图都是某个对象(subject, publisher)改变,使依赖于它的多个对象(observers, subscribers)得到通知。 区别与适用场景总的来说,发布-订阅模式适合更复杂的场景。 在「一对多」的场景下,发布者的某次更新只想通知它的部分订阅者? 在「多对一」或者「多对多」场景下。一个订阅者依赖于多个发布者,某个发布者更新后是否需要通知订阅者?还是等所有发布者都更新完毕再通知订阅者? 这些逻辑都可以放到ChangeManager里。 |
应该是观察者模式。 vue的事件通讯机制才是发布订阅模式 |
数据劫持+发布订阅 |
从命名上就可以区别,观察者(observer)和主题(subject)对象 |
观察者模式为一刀切模式,对所有订阅者一视同仁 |
发布-订阅增加了一个中介者,发布者和订阅着只和中介者打交到。中介者持有发布者和订阅者都引用或传入的回调,用来做订阅和通知。 |
观察者模式由具体目标调度,每个被订阅的目标里面都需要有对观察者的处理,会造成代码的冗余。而发布订阅模式则统一由调度中心处理,消除了发布者和订阅者之间的依赖。 |
低耦合和完全解藕 |
多个发布订阅构成观察者模式,触发条件的话,感觉都是类似监听的方式,区别不明显 |
参考了Java的部分实现,观察者模式代码如下:
而使用订阅发布模式,使用中间订阅发布对象的方式如下
自己认为,两种模式本质都是一样的,主要关键点都在于注册(添加到注册数组中)和触发(触发注册数组中的内容),只是订阅/发布模式对注册和触发进行了解耦。可以看到,使用订阅发布模式中发布者触发publish的时候,可以选择触发哪一些订阅者集合(因为publish参数传递了中间集合,可以定义多个pubsub集合),而观察者模式则只能触发所有的被观察对象。 |
vue双向绑定过程涉及发布订阅和观察者,setter是观察者,更新的过程是发布订阅 |
应该是发布订阅模式吧,订阅发布模式说的应该和观察者模式是同一个模式的两种叫法吧 |
还是看代码清楚 |
确定是赚了差价吗,应该算是亏本买卖吧,毕竟有投入的 |
观察者模式就像 mvvm ,m的变化v可以感知而对应的做出变化(不是很准确,因为观察者是单向的) |
我的回答:观察者模式: 假如现在有一个楼盘将要开盘(这个楼盘是一个主体,里面有销售人员,有保安人员等等), 然后有很多人(很多观察者)来买房,然后这些人把自己的电话留在售楼部(每个观察者都把自己注册到目标), 当确定楼盘开盘日期的时候,就由售楼部的销售人员通知这些留下电话的买房的人。 在这里,买房的人必须把自己的电话号码留在售楼部(观察者必须把自己注册到主体里), 不然楼盘的销售人员是无法通知要买房的人的,这之间就产生了联系。 发布订阅模式: 假设有一个中介,有很多想把自己的房子卖了的人,就把自己的房产信息留下。 然后有很多想要买二手房的人,把自己的电话也留在了中介。 这之间,买房的和卖房的一点关系都没有,谁都不知道谁的存在,买房的等着中介通知它有没有房。 |
应用到react上 ,观察者模式是不是就像父子组件传值 而发布订阅模式就像是组件之间信息通过redux传递呢。 |
观察者模式和发布订阅模式都有观察者和发布这两个对象 观察者模式没有中介,发布者和订阅者必须知道对方的存在 发布订阅模式有中介,发布者和订阅者不需要知道对方是谁,只要通过中介进行信息的传递和过滤就可以了 这是最大的不同 |
观察者模式和发布-订阅模式的共同点在于都是发布者发布信息使得订阅者发起修改 |
mvvm 模式 m 和v 也需要vm 来赚中间差价,你这样理解观察者模式是不是有点问题呢? |
对滴 |
观察者模式就像你在酒店直接给技师打电话让技师过来服务,发布订阅就像你先去xxx会所然后到了以后会所给你安排技术服务。。。不知道我理解得有没有问题 |
观察者模式由具体目标调度,每个被订阅的目标里面都需要有对观察者的处理,会造成代码的冗余。而发布订阅模式则统一由调度中心处理,消除了发布者和订阅者之间的依赖 |
我的理解是,举个例子:观察者模式相等于A在文章写好之后直接发送给B和C进行查看,也就是说A与B、C直接强关联, |
双向绑定的效果可以理解成观察者模式,单向数据流的效果可以理解成发布订阅模式 生活化一点就是: 发布者就是资源的生产者,而订阅者就是需要资源的人(也就是消费者),我们是线下面对面交易?还是网上交易? |
举个例子:观察者模式好比用户从品牌厂家提车,厂家发货了用户能直接收到通知; |
在 JS 中,事件订阅应该属于发布-订阅模式。比如 EventBus,对注册的多种事件,可以单独触发,比如只触发 A 事件,则订阅的 B 事件并不会处理。 |
发布订阅模式发布订阅模式叫观察者模式。 举一个生活中的例子,很多了订阅了一个博客,相当于触发了一个 实际应用有 Vue 中的 (1)介绍 这样说可能难理解,简单的说,写一个构造函数,像这样:
现在我们要订阅一件事,就是给构造函数添加一个方法,像这样: EventEmitter.prototype.on = function(name, cb){
}
// 参数1:函数名
// 参数2:要执行的函数 事件订阅好了,该发布了,这样: EventEmitter.prototype.emit = function(name,...args){
}
// 参数1: 要触发的函数名
// 参数2: 需要给函数传入的参数 当时机到时,你通过 emit 传入一个函数名来执行自己定义好的函数。 如果我们以后不用一个事件,那么应该把他移除掉对吧。 EventEmitter.prototype.off = function(name){
} 骨架搭建好了,先模拟用一下,不着急实现,首先要知道怎么用对吧。 // 创建实例
var emitter = new EventEmitter();
// 订阅一个事件
emitter.on("sayHi", function(data){
console.log(data)
})
// 发布一个消息
emitter.emit("sayHi","Hi") // 执行sayHi函数,应该打印 Hi 这个就是大概的流程,下面我们开始实现。 (2)实现 我们看到,在 on 里有一个回调函数,在emit 的时候执行,所以我们在构造函数中添加一个对象,保存这些函数。 function EventEmitter(){
this.list = {}
} 现在可以实现 EventEmitter.prototype.on = function (name, cb) {
if (this.list[name]) {
this.list[name].push(cb) // 追加方法
} else {
this.list[name] = [cb]; // 创建一个name事件
}
} 我们先应该判断一下是否有这个方法,要不然会覆盖之前写的方法,如果存在我们追加这个函数即可。 不存在这个方法,我们以 name 为名字创建一个数组,把函数添加即可。 现在实现 EventEmitter.prototype.emit = function (name, ...args) {
let _this = this;
// 如果事件不存在返回 false
if (!this.list[name]) return false;
// 遍历 this.list[name] 中的每一个函数并执行
this.list[name].forEach(fn => {
fn.apply(this, args);
})
return true;
} 还有一个 EventEmitter.prototype.off = function (name, fn) {
// 如果事件不存在返回 false
if (!this.list[name]) return false;
// 循环数组找到该函数并移除
for (let i = 0; i < this.list[name].length; i++) {
if (this.list[name][i] == fn) {
this.list[name].splice(i, 1);
}
}
return true
} 基本功能实现了,使用试一下: var emitter = new EventEmitter();
// 用户1 添加订阅
function sayHi1(data) {
console.log(data, "user1")
}
emitter.on("sayHi", sayHi1)
// 用户2 添加订阅
function sayHi2(data) {
console.log(data, "user2")
}
emitter.on("sayHi", sayHi2)
// 取消 user1 的订阅
emitter.off("sayHi", sayHi1)
// 发布
emitter.emit("sayHi", "订阅者")
// 打印
// 订阅者 user2 用 class 语法重写了一下完整的。 class EventEmitter {
constructor() {
this.list = {}
}
on(name, cb) {
if (this.list[name]) {
this.list[name].push(cb) // 追加方法
} else {
this.list[name] = [cb]; // 创建一个name事件
}
}
emit(name, ...args) {
let _this = this;
// 如果事件不存在返回 false
if (!this.list[name]) return false;
// 遍历 this.list[name] 中的每一个函数并执行
this.list[name].forEach(fn => {
fn.apply(_this, args);
})
return true;
}
off(name, fn) {
// 如果事件不存在返回 false
if (!this.list[name]) return false;
// 循环数组找到该函数并移除
for (let i = 0; i < this.list[name].length; i++) {
if (this.list[name][i] == fn) {
this.list[name].splice(i, 1);
}
}
return true
}
} 来源:js设计模式 |
23三种设计模式中根本就没有上面说的发布—订阅模式。 |
This comment has been minimized.
This comment has been minimized.
// 订阅模式
class eventEmitter1 {
list = []
on(event, fn) {
(this.list[event] || (this.list[event] = [])).push(fn)
}
off(event, fn) {
const curList = this.list[event] || []
if (!curList.length) {
return false
}
if (!fn) {
curList.length = 0
}
for (const inx of Object.keys(curList)) {
const val = curList[inx]
if (val.fn === fn || val === fn) {
curList.splice(inx, 1)
break
}
}
}
once(event, fn) {
const curList = this.list[event] || []
function on() {
fn.apply(this, arguments)
on.fn = fn
this.off(event, fn)
}
// on.fn = fn
this.on(event, on)
}
emit() {
const curList = this.list[Array.prototype.shift.call(arguments)]
const params = [...arguments]
if (!curList.length) {
return false
}
console.log(curList);
for (const val of curList) {
val.apply(this, params)
}
}
}
function user1(content) {
console.log('用户1订阅了:', content);
}
function user2(content) {
console.log('用户2订阅了:', content);
}
function user3(content) {
console.log('用户3订阅了:', content);
}
function user4(content) {
console.log('用户4订阅了:', content);
}
const eventEmitter = new eventEmitter1()
// 订阅
// eventEmitter.on('article1', user1);
// eventEmitter.on('article1', user2);
// eventEmitter.on('article1', user3);
// // 取消user2方法的订阅
// eventEmitter.off('article1', user2);
// eventEmitter.off('article1', null);
eventEmitter.once('article2', user4)
// 发布
// eventEmitter.emit('article1', 'Javascript 发布-订阅模式');
// eventEmitter.emit('article1', 'Javascript 发布-订阅模式');
eventEmitter.emit('article2', 'Javascript 观察者模式');
eventEmitter.emit('article2', 'Javascript 观察者模式1'); |
观察者模式和发布订阅模式的设计思想是类似的,只是在应用场景上和实现策略上略有不同而已。 |
您的邮件已收到!O(∩_∩)O!--------Pan
|
观察者模式中主体和观察者是互相感知的,发布-订阅模式是借助第三方来实现调度的,发布者和订阅者之间互不感知
The text was updated successfully, but these errors were encountered: