观察者模式

The Observer is a design pattern where an object (known as a subject) maintains a list of objects depending on it (observers), automatically notifying them of any changes to state.

观察者是一种 包含一系列依赖于主体(subject)的观察者(observers),自动通知它们变化的内容的设计模式


接下来,用oberver pattern来实现一个购物车列表,实现之前先说明几个概念:

主体 (Subject)

维护一系列观察者的数组,包含一些操作方法,比如增加、删除,获取等等。

class Subject {constructor() {this.observerList = [];}add(item) { //添加return this.observerList.push(item);}count() { //获取长度return this.observerList.length;}get(index) { //获取下标if (index > -1 && index < this.observerList.length) {return this.observerList[index];} else {return null;}}notify(context) { //通知let observerCount = this.count();for (let i = 0; i < observerCount; i++) {console.dir(this.get(i))this.get(i).update(context);}}
}

首先我们声明一个主体类,里面包含一个观察者数组,还有一些操作方法。

观察者(Observer)

class Observer {constructor() {this.update = () => { //通用interface//todo}}
}

声明一个更新接口,用来获取主体分发的通知。

两者关系大概如下:

主要流程:

  1. 定义好主体类和观察者类
  2. 类实例化成具体对象,绑定方法,观察者在主体对象里注册
  3. 操作。主体分发消息给观察者。

具体实现代码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><style>table tr td {text-align: center;}</style>
</head><body><p>name:<input type="text" style="width:100px" id="name"> price:<input type="text" style="width:50px" id="price"><input type="button" id="btn" value="Add"><input type="text" style="width:50px" id="priceAdd"><input type="button" id="priceAddBtn" value="priceAdd"></p><table><caption>list</caption><thead><tr><th>name</th><th>price</th><th>action</th></tr></thead><tbody id="main"></tbody></table><script>//被观察类class Subject {constructor() {this.observerList = [];}add(item) { //添加return this.observerList.push(item);}count() { //获取长度return this.observerList.length;}get(index) { //获取下标if (index > -1 && index < this.observerList.length) {return this.observerList[index];} else {return null;}}notify(context) { //通知let observerCount = this.count();for (let i = 0; i < observerCount; i++) {console.dir(this.get(i))this.get(i).update(context);}}}//观察类class Observer {constructor() {this.update = () => { //通用interface//todo}}}//合并对象方法let extend = (source, extendsion) => {let ext = new extendsion(),properties = Object.getOwnPropertyNames(ext),protoProperties = Object.getOwnPropertyNames(extendsion.prototype);// to get all propertiesproperties.forEach(function(val, key) {source[val] = ext[val];if (key == properties.length - 1) {protoProperties.forEach(function(innerVal, key) {if (val != 'constructor') {source[innerVal] = extendsion.prototype[innerVal];}})}})}let btn = document.getElementById('btn');let priceAdd = document.getElementById('priceAddBtn');//挂载主体extend(btn, Subject);//extend(priceAdd, Subject);//按钮btn.addEventListener('click', function() {let tBody = document.getElementById('main'),name = document.getElementById('name'),price = document.getElementById('price'),dataSet = {name: name.value,price: price.value};let html = document.createElement('tr');//模版let item =`<td class="name">${dataSet.name}</td><td class="price">${dataSet.price}</td><td><button type="button" onclick='del(this)'>delete</button></td>`;html.innerHTML = item;btn.add(html); //observer放入subjectextend(html, Observer); //继承观察类html.update = function(context) { //更新contextlet num = Number(this.querySelector('.price').innerHTML);this.querySelector('.price').innerHTML = num + context;};tBody.appendChild(html);});priceAdd.addEventListener('click', function() {let num = document.getElementById('priceAdd').value;btn.notify(Number(num));})//删除当前行function del(obj) {let _this = obj,box = _this.parentNode.parentNode.parentNode;box.removeChild(_this.parentNode.parentNode);}</script>
</body></html>

发布/订阅者模式

The Publish/Subscribe pattern however uses a topic/event channel which sits between the objects wishing to receive notifications (subscribers) and the object firing the event (the publisher). This event system allows code to define application specific events which can pass custom arguments containing values needed by the subscriber. The idea here is to avoid dependencies between the subscriber and publisher.

Publish/Subscribe pattern和Observer pattern和类似,都是Observer注册,subject分布通知,但是Publish/Subscribe pattern多了个事件管道(event channel)用来集中处理监听的事件

典型的Publish/Subscribe模式的实现代码:

var pubsub = {};(function(myObject) {// Storage for topics that can be broadcast// or listened tovar topics = {};// An topic identifiervar subUid = -1;// Publish or broadcast events of interest// with a specific topic name and arguments// such as the data to pass along  myObject.publish = function(topic, args) {if (!topics[topic]) {return false;}var subscribers = topics[topic],len = subscribers ? subscribers.length : 0;while (len--) {subscribers[len].func(topic, args);}return this;};// Subscribe to events of interest// with a specific topic name and a// callback function, to be executed// when the topic/event is observedmyObject.subscribe = function(topic, func) {if (!topics[topic]) {topics[topic] = [];}var token = (++subUid).toString();topics[topic].push({token: token,func: func});return token;};// Unsubscribe from a specific// topic, based on a tokenized reference// to the subscriptionmyObject.unsubscribe = function(token) {for (var m in topics) {if (topics[m]) {for (var i = 0, j = topics[m].length; i < j; i++) {if (topics[m][i].token === token) {topics[m].splice(i, 1);return token;}}}}return this;};}(pubsub));

test demo:

        //注册事件var test = pubsub.subscribe('message', function(topic, data) {console.log("topic:" + topic + ",data:" + data);});//分布消息pubsub.publish('message', "siip"); //topic:message,data:test,a,b,cpubsub.publish("message", ["test", "a", "b", "c"]); //topic:message,data:test,a,b,c//删除注册事件pubsub.unsubscribe(test);pubsub.publish("message", {sender: "hello@google.com",body: "Hey again!"});

两者关系大概如下:

参考:

1、https://addyosmani.com/resour...

2、http://blog.csdn.net/cooldrag...

js设计模式之观察者模式和发布/订阅模式相关推荐

  1. JavaScript 设计模式之观察者模式与发布订阅模式

    前言 在软体工程中,设计模式(design pattern)是对软体设计中普遍存在(反复出现)的各种问题,所提出的解决方案. 设计模式并不直接用来完成程式码的编写,而是描述在各种不同情况下,要怎么解决 ...

  2. 游戏服务器架构-设计模式之观察者模式和发布订阅模式真的一样吗?

    前面我给大家分享了观察者模式和发布订阅模式,有人私信给我说这俩不是一样嘛,大体没什么区别,我猜测大多数认为这两者是一样的可以继续阅读这两篇文章,如果还不能解答你的问题,我相信这篇文章对比两者的关系会让 ...

  3. C++设计模式之观察者模式和发布订阅模式

    在软件工程中,设计模式(Design Pattern)是对软件设计普遍存在(反复出现)的各种问题,锁提出的解决防范.根据模式的目的来划分的话,GoF(Gang of Four) 设计模式可以分为以下三 ...

  4. 2.设计模式-观察者模式(发布-订阅模式)

    观察者模式(发布-订阅模式)一个简单的使用 简介 例子 被监听者(被观察者) 监听者(观察者) 测试类 简介 观察者模式(有时又被称为模型(Model)-视图(View)模式.源-收听者(Listen ...

  5. JS观察者模式和发布订阅模式

    观察者模式 观察者模式在前端工程中是很常见的设计模式,因为前端交互中充斥着大量多控件联动的交互,当参与联动的组件数量比较多或者组件数量可能变化的时候,代码就会变得难以维护.但是如果我们写代码时遵循了观 ...

  6. JS观察者模式和发布订阅模式的区别

    观察者模式: 观察者观察被观察者,当被观察者发生被观察的行为时,触发观察者里面的事件. document.querySelector('#btn').addEventListener('click', ...

  7. 深入理解观察者模式与发布订阅模式

    观察者模式与发布订阅模式区别 (全文很长,认真读完相信你会有所收获) 纸上得来终觉浅 观察者模式与发布订阅模式区别 抽象模型 观察者模式 发布-订阅模式 结论 困惑 发布订阅模式?? jQuery的发 ...

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

    一.前言 观察者模式vs发布/订阅模式很容易混淆,像是凤梨和菠萝,傻傻分不清.Observer模式通常用Publish/Subscribe模式实现,我刚开始学习js的时候,以为这是同一回事,但是仔细学 ...

  9. 观察者模式VS发布-订阅模式

    前言 观察者模式的大名,想必各位看官早已有所耳闻.从我们现实生活来说,微信公众号订阅.医院挂号叫号等都属于它的实际应用.在程序世界中,它是一种用于将代码解耦的设计模式,如果你想掌握并理解这种设计模式, ...

最新文章

  1. 中国有神经网络计算机,新神经网络使计算机像人一样推理
  2. AzureDirectory Library for Lucene.Net
  3. python里面的之前打过的记忆信息-Python关键语句备忘录,拯救你的记忆
  4. 【专访】小米产品经理颠覆早教行业,欲送给孩子1000万美金的人生
  5. Mybatis Plus为什么提供BaseMapper和IService两个相似CRUD操作的接口?
  6. 不认识java代码_程序员进阶:优雅的代码对于一个架构师的重要性
  7. java 二进制反码_Java学习第五篇:二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题...
  8. VMware演示手机虚拟化
  9. x86异常处理与中断机制(2)中断向量表
  10. 计算机系统账户被锁定,帐号已经被系统锁定是什么意思
  11. 为程序员节省时间的习惯
  12. 对称密钥和非对称密钥有什么区别,区别在哪里
  13. Jmeter使用CSV文件读取大量测试数据
  14. 港股历史行情数据 API 接口
  15. Spring boot 集成 Kaptcha 实现前后端分离验证码功能
  16. Design contains shelved or modified (but not repoured) polygons. The result of DRC is not correct.
  17. WPS:WPS的论文使用技巧之如何对不同章节设置不同的页眉(图文教程)
  18. 高阶人工智能时代的畅想
  19. 机器学习常见英语单词解释
  20. 【调研】国内芯片公司对于存算一体芯片的相关调研

热门文章

  1. 创建生成级联上级字符的函数
  2. 数据库表结构设计方法
  3. 安装zabbix服务器端
  4. rdlc报表的制作步骤
  5. 《团队-科学计算器-模块开发过程》
  6. 用leangoo怎么做需求管理及规划?(产品Backlog、用户故事)
  7. 利用 Composer 一步一步构建自己的 PHP 框架(四)——使用 ORM
  8. 电脑休眠跟睡眠的区别
  9. Oracle - 导入异常ORA-01659和11G在Exp时空表不能导出
  10. Linux 用户磁盘空间配额管理