We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
使用观察者模式的好处:
我们先用一个通俗的情景来比喻一下,就拿 航班 与 航站楼 之间的关系:
图上显示的是 飞机1在从 北京 飞往 南京, 北京航站楼A 和 南京航站楼B 都需要关注 飞机1 的信息, 而 飞机1 在位置变化 之后也要及时的 通知 北京航站楼A 和 南京航站楼。 (其实可以看出来,这里 航站楼是被动的接受 飞机是主动的发出变化)
所以,我们可以写一个简单的 观察/订阅模式
function Observer () { // 数组存放多个观察者 this.fns = []; } Observer.prototype = { // 订阅 (飞机信息) sub: function (fn) { this.fns.push(fn); }, // 退订 (飞机信息) unsub: function (fn) { this.fns = this.fns.filter(function(el) { if (el !== fn) { return el; } }) }, // 发布 (飞机信息变化时) publish: function (o, thisObj) { var scope = thisObj || window; this.fns.forEach(function(el) { el.call(scope, o); }); } }
var ob = new Observer;
初始化 飞机1 的地理位置
var location = '北京';
定义 2 个航站楼的行为
// 北京 航站楼A - 观察者 var hangzhanlouBeijing = function (data) { console.log('北京航站楼 收到了数据变化的通知,我知道现在 飞机1 的位置了,是在:' +data); // 做一些操作 }; // 南京 航站楼B - 观察者 var hangzhanlouNanjing= function (data) { console.log('南京航站楼 收到了数据变化的通知,我知道现在 飞机1 的位置了,是在:' +data + ',我这就准备接机'); // 做一些操作 };
南京和北京航站楼开始订阅(注册),将要关注 飞机1 的地址位置
// 订阅 (飞机地理位置的变化) ob.sub(hangzhanlouBeijing); ob.sub(hangzhanlouNanjing);
飞机1 经过一段时间的飞行 从 北京 到了 南京 ,这时候地理位置发生了变化
// 经过一些 操作 导致 location 发生了变化 location = '南京';
重要 然后 检查(校验) location(地址位置) 是否发生变化,如果发生变化,就进行通知
// 数据 location 发生变化(现在的值 不等于 原来的值) if (location!== '北京') { // 发布 数据变化了(确认地址位置变了 ),广播 所有订阅(关注) 飞机1 的观察者(航站楼) ob.update(location); }
输出
北京航站楼 收到了数据变化的通知,我知道现在 飞机1 的位置了,是在: 南京 南京航站楼 收到了数据变化的通知,我知道现在 飞机1 的位置了,是在: 南京,我这就准备接机
情况一: 因为这里我们只有一架 飞机1 具有了 观察者模式,如果再来一架 飞机2 也是从 北京 飞往 南京 的呢?很明显,我们也需要知道 飞机2 的地理位置信息
情况二: 还有假如 北京航站楼 只关注 飞机1 的变化,而不关注 飞机2 的变化,同理, 南京航站楼 只关注 _飞机2_的变化, 而不关注 飞机1 的变化
那这样情况就比较复杂了
学术一点的意思就是:要让多个对象都具有观察者模式(让 多个 观察者 可以关注 多个 自己想关注的 观察对象)。
观察者
观察对象
这时候分析下,相比较之前有什么变化
用图表示 应该就是下面这种 数据情景
所以这里 我们定义的一个通用函数 ,它应该具备 上述的 一些特性
也就是说:每个观察者对象,都独立维护一套独立的观察者模式。
根据需要,我们抽象出下面 这样一个通用的函数:
//通用代码 var observer = { //订阅 addSubscriber: function (callback) { this.subscribers[this.subscribers.length] = callback; }, //退订 removeSubscriber: function (callback) { for (var i = 0; i < this.subscribers.length; i++) { if (this.subscribers[i] === callback) { delete (this.subscribers[i]); } } }, //广播 publish: function (what) { for (var i = 0; i < this.subscribers.length; i++) { if (typeof this.subscribers[i] === 'function') { this.subscribers[i](what); } } }, // 通过遍历,给 观察者对象 o 添加 观察者容器,订阅,退订,发布 make: function (o) { for (var i in this) { o[i] = this[i]; // 每个 观察者对象 都维护自身的一个 观察者 数组 o.subscribers = []; } } };
OK,已经抽象出了 具体的 范式,下面就结合具体情景来看下看是否符合
下面 先分别定义 飞机1,飞机2 这两个观察者对象的 多个属性(地理位置 和 海拔)
var plan1 = { location: '北京', height: '200km' } var plan2 = { location: '云南', height: '100km' }
再,分别定义 观察者 的行为(航站楼1,航站楼2 分别关注 飞机的运行状态)
var hangzhanlou1 = function hangzhanlou1(cb) { console.log('航站楼1 收到了 我关注的 飞机 的运行状态发生了改变...') // 订阅的对象发生了变化 , 观察者 做一些自己想做的事... cb(); } var hangzhanlou2 = function hangzhanlou2 (cb) { console.log('航站楼2 收到了 我关注的 飞机 的运行状态发生了改变...') // 订阅的对象发生了变化 , 观察者 做一些自己想做的事... cb(); }
这里,航站楼1 可以 订阅 飞机1,也可以订阅 飞机2 ,也可以都订阅
同样,航站楼1 可以订阅 飞机的 位置,也可以订阅飞机的 海拔, 也可以都订阅
给 飞机1,飞机2的 地理位置,海拔高度 都 添加 观察者模式
observer.make(plan1); observer.make(plan2);
添加 观察者 hangzhanlou1
plan1.addSubscriber(hangzhanlou1)
飞机1 经过飞行,判断 关注的信息是否发生了变化
这里判断是伪代码,但是这个判断的逻辑非常!非常!非常!的重要!如果有时间,这个后续会展开讲解,因为这里是另外一个核心内容,diff变化,从而控制View层的渲染!
// 这里为了演示方便,默认判断 地理,海拔都变化了(其实也可以判断 观察者某一个 属性) function checkChange(val, oldVal) { if (val !== oldVal) { plan1.publish(function(){ console.log('飞机1 现在位置是上海,海拔是100km'); }) } } // 航站楼1 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机1 现在位置是上海,海拔是100km
plan1.addSubscriber(hangzhanlou2)
同样判断状态的改变,进行发布
function checkChange(val, oldVal) { if (val !== oldVal) { plan1.publish(function(){ console.log('飞机1 现在位置是太原,海拔是120km'); }) } } // 航站楼1 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机1 现在位置是太原,海拔是120km // 航站楼2 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机1 现在位置是太原,海拔是120km
plan2.addSubscriber(hangzhanlou1)
function checkChange1(val, oldVal) { if (val !== oldVal) { plan1.publish(function(){ console.log('飞机1 现在位置是青海,海拔是300km'); }) } } // 航站楼1 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机1 现在位置是青海,海拔是300km // 航站楼2 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机1 现在位置是青海,海拔是300km function checkChange2(val, oldVal) { if (val !== oldVal) { plan2.publish(function(){ console.log('飞机2 现在位置是西藏,海拔是500km'); }) } } // 航站楼2 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机2 现在位置是西藏,海拔是500km
添加 观察者 hangzhanlou2
plan2.addSubscriber(hangzhanlou2)
function checkChange1(val, oldVal) { if (val !== oldVal) { plan1.publish(function(){ console.log('飞机1 现在位置是青海,海拔是300km'); }) } } // 航站楼1 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机1 现在位置是青海,海拔是300km // 航站楼2 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机1 现在位置是青海,海拔是300km function checkChange2(val, oldVal) { if (val !== oldVal) { plan2.publish(function(){ console.log('飞机2 现在位置是西藏,海拔是500km'); }) } } // 航站楼1 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机2 现在位置是西藏,海拔是500km // 航站楼2 收到了 我关注的 飞机 的运行状态发生了改变... // 飞机2 现在位置是西藏,海拔是500km
在 飞机1 上移除 观察者 hangzhanlou2
plan1.removeSubscriber(hangzhanlou2)
观察者模式大体就是如此,但是在开发中为了适应各种场景可能会有很多变种,但是万变不离其中。
上面的代码只是用来帮助理解的,针对 航班 与 航站楼 这种情景 还有很多改进的地方。
以上只是个人理解的一些拙见,如有不对之处还请海涵,并希望大家帮忙纠正!
The text was updated successfully, but these errors were encountered:
👍
Sorry, something went wrong.
No branches or pull requests
观察者模式
观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
使用观察者模式的好处:
理解的第一阶段
我们先用一个通俗的情景来比喻一下,就拿 航班 与 航站楼 之间的关系:
图上显示的是 飞机1在从 北京 飞往 南京, 北京航站楼A 和 南京航站楼B 都需要关注 飞机1 的信息,
而 飞机1 在位置变化 之后也要及时的 通知 北京航站楼A 和 南京航站楼。
(其实可以看出来,这里 航站楼是被动的接受 飞机是主动的发出变化)
所以,我们可以写一个简单的 观察/订阅模式
初始化 飞机1 的地理位置
定义 2 个航站楼的行为
南京和北京航站楼开始订阅(注册),将要关注 飞机1 的地址位置
飞机1 经过一段时间的飞行 从 北京 到了 南京 ,这时候地理位置发生了变化
重要 然后 检查(校验) location(地址位置) 是否发生变化,如果发生变化,就进行通知
输出
理解的第二阶段
情况一:
因为这里我们只有一架 飞机1 具有了 观察者模式,如果再来一架 飞机2 也是从 北京 飞往 南京 的呢?很明显,我们也需要知道 飞机2 的地理位置信息
情况二:
还有假如 北京航站楼 只关注 飞机1 的变化,而不关注 飞机2 的变化,同理, 南京航站楼 只关注 _飞机2_的变化, 而不关注 飞机1 的变化
那这样情况就比较复杂了
学术一点的意思就是:要让多个对象都具有观察者模式(让 多个
观察者
可以关注 多个 自己想关注的观察对象
)。这时候分析下,相比较之前有什么变化
用图表示 应该就是下面这种 数据情景
所以这里 我们定义的一个通用函数 ,它应该具备 上述的 一些特性
也就是说:每个观察者对象,都独立维护一套独立的观察者模式。
根据需要,我们抽象出下面 这样一个通用的函数:
OK,已经抽象出了 具体的 范式,下面就结合具体情景来看下看是否符合
下面 先分别定义 飞机1,飞机2 这两个观察者对象的 多个属性(地理位置 和 海拔)
再,分别定义 观察者 的行为(航站楼1,航站楼2 分别关注 飞机的运行状态)
这里,航站楼1 可以 订阅 飞机1,也可以订阅 飞机2 ,也可以都订阅
同样,航站楼1 可以订阅 飞机的 位置,也可以订阅飞机的 海拔, 也可以都订阅
给 飞机1,飞机2的 地理位置,海拔高度 都 添加 观察者模式
添加 观察者 hangzhanlou1
飞机1 经过飞行,判断 关注的信息是否发生了变化
这里判断是伪代码,但是这个判断的逻辑非常!非常!非常!的重要!如果有时间,这个后续会展开讲解,因为这里是另外一个核心内容,diff变化,从而控制View层的渲染!
添加 观察者 hangzhanlou2
同样判断状态的改变,进行发布
添加 观察者 hangzhanlou1
同样判断状态的改变,进行发布
添加 观察者 hangzhanlou2
同样判断状态的改变,进行发布
在 飞机1 上移除 观察者 hangzhanlou2
最后
观察者模式大体就是如此,但是在开发中为了适应各种场景可能会有很多变种,但是万变不离其中。
上面的代码只是用来帮助理解的,针对 航班 与 航站楼 这种情景 还有很多改进的地方。
以上只是个人理解的一些拙见,如有不对之处还请海涵,并希望大家帮忙纠正!
拓展阅读
The text was updated successfully, but these errors were encountered: