博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript 设计模式----观察者模式
阅读量:3947 次
发布时间:2019-05-24

本文共 5144 字,大约阅读时间需要 17 分钟。

JavaScript 设计模式----观察者模式

1. 观察者模式

1.1 观察者模式介绍

  • 发布 & 订阅
  • 一对多
  • 示例
    • 点咖啡,点好之后坐等被叫

1.2 观察者模式类图

  • 传统 UML 类图
    在这里插入图片描述
  • 简化后的 UML 类图
    在这里插入图片描述
    • 左侧 Observer观察者,有一个 update() 触发方法
    • 右侧 Subject主题,可以绑定多个观察者
      • Subject 中的 observers 是个数组 Array
      • 能够获取状态 getState()
      • 能够设置状态 setState()
      • 设置状态后,会触发所有的观察者里的 update 方法

1.3 观察者模式演示

// 主题,保存状态,状态变化之后触发所有观察者对象class Subject {
constructor() {
this.state = 0 this.observers = [] } getState() {
return this.state } setState(state) {
this.state = state this.notifyAllObservers() } notifyAllObservers() {
// 此方法将当前所有观察者 observers,进行遍历 this.observers.forEach(observer => {
// 每个观察者都执行 update() 方法 observer.update() }) } attach(observer) {
// 添加新的观察者 this.observers.push(observer) }}// 观察者class Observer {
constructor(name, subject) {
this.name = name this.subject = subject this.subject.attach(this) // 把观察者添加到当前主题中来 } update() {
// 当触发观察者的 update 方法之后,把 Subject 中的状态 state 打印出来 console.log(`${
this.name} update, state: ${this.subject.getState()`) }}// 测试let s = new Subject()let o1 = new Observer('o1', s)let o2 = new Observer('o2', s)let o3 = new Observer('o3', s)s.setState(1)s.setState(2)s.setState(3)

1.4 观察者模式场景

1.4.1 网页事件绑定
  • 网页事件绑定以及所有的UIwebview这种层面的事件监听的机制全部用观察者模式
    • 比如监听用户点击、拖拽
  • 如果不用观察者模式,那代码开发就会比较难理解
1.4.2 Promise
// 如何生成一个Promise,并且返回Promisefunction loadImg(src) {
var promise = new Promise(function (resolve, reject) {
var img = document.createElement('img') img.onload = function () {
resolve(img) } img.onerror = function () {
reject('图片加载失败') ] img.src = src }) return promise}
// 发布订阅的关系var src = 'https://www.imooc.com/static/img/index/logo_new.png'var result = loadImg(src)result.then(function (img) {
// 先绑定函数,不会立刻执行,因为加载图片是需要时间去处理 console.log('width', img.width) return img}).then(function (img) {
// 需要等Promise的状态变化才执行 console.log('height', img.height)})
1.4.3 jQuery 中 callbacks
// 自定义事件,自定义回调var callbacks = $.Callbacks() // 注意大小写callbacks.add(function (info) {
console.log('fn1', info)})callbacks.add(function (info) {
console.log('fn2', info)})callbacks.add(function (info) {
console.log('fn3', info)})callbacks.fire('gogogo')callbacks.fire('fire')
1.4.4 Nodejs 自定义事件
const EventEmitter = require('events').EventEmitter // 引用基础apiconst emitter1 = new EventEmitter()emitter1.on('some', () => {
// 监听 some 事件 console.log('some event is occured 1')})emitter1.on('some', () => {
// 监听 some 事件 console.log('some event is occured 2')})// 触发 some 事件emitter1.emit('some')
const EventEmitter = require('events').EventEmitterconst emitter = new EventEmitter()emitter.on('showName', name => {
console.log('event occured', name)})emitter.emit('showName', 'zhangsan') // emit 时候可以传递参数过去
  • EventEmitter 事件被其他功能继承使用
const EventEmitter = require('events').EventEmitter// 任何构造函数都可以继承 EventEmitter 的方法 on emitclass Dog extends EventEmitter {
constructor(name) {
super() this.name = name }}var simon = new Dog('simon')simon.on('back', function () {
console.log(this.name, 'barked')})setInterval(() => {
simon.emit('back')}, 500)
// Stream 用到了自定义事件,监听流数据var fs = require('fs')var readStream = fs.createReadStream('./data/file1.txt') // 读取文件的 Streamvar length = 0readStream.on('data', function (chunk) {
length += chunk.toString().length})readStream.on('end', function () {
console.log(length)})
// readline 用到了自定义事件,监听行数据var readline = require('readline');var fs = require('fs')var rl = readline.createInterface){
input: fs.createReadStream('./data/file1.txt')});var lineNum = 0rl.on('line', function(line) {
lineNum++});rl.on('close', function() {
console.log('lineNum', lineNum)});
1.4.5 其他场景
  • Node.js 中:处理 http 请求;多进程通讯
// 处理 http 请求function serverCallback(req, res) {
var method = req.method.toLowerCase() // 获取请求的方法 if (method === 'get') {
// 省略 3 行,上文代码示例中处理 GET 请求的代码 } if (method === 'post') {
// 接收 post 请求的内容 var data = '' req.on('data', function (chunk) {
// "一点一点" 接收内容 data += chunk.toString() }) req.on('end', function () {
// 接收完毕,将内容输出 res.writeHead(200, {
'Content-type': 'text/html'}) res.write(data) res.end() }) }}
// 多进程通讯 parent.jsvar cp = require('child_process')var n = cp.fork('./sub.js')n.on('message', function (m) {
console.log('PARENT got message: ' + m)})n.send({
hello: 'world'})// sub.jsprocess.on('message', function (m) {
console.log('CHILD got message: ' + m)})process.send({
foo: 'bar' })
  • Vue 和 React 组件生命周期触发
// Reactclass Login extends React.Component {
constructor(props, context) {
super(props, context); this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); this.state = {
checking: true } } render() {
return (
) } componentDidMount() {
// 判断是否已经登录 this.doCheck() }}
  • Vue watch
// Vuevar vm = new Vue({
el: '#demo', data: {
firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName }, lastName: function (val) {
this.fullName = this.firstName + ' ' + val } }})

1.5 观察者模式设计原则验证

  • 主题和观察者分离,不是主动触发而是被动监听,两者解耦
  • 符合开放封闭原则

转载地址:http://ecqwi.baihongyu.com/

你可能感兴趣的文章
Parsing XML Data
查看>>
Optimizing Downloads for Efficient Network Access
查看>>
Minimizing the Effect of Regular Updates
查看>>
Redundant Downloads are Redundant
查看>>
Modifying your Download Patterns Based on the Connectivity Type
查看>>
Supporting Different Screen Sizes支持不同的屏幕尺寸
查看>>
Supporting Different Densities 支持各种屏幕密度
查看>>
Implementing Adaptative UI Flows 实施自适应用户界面流程
查看>>
Crossfading Two Views 淡入淡出的两种观点
查看>>
Using ViewPager for Screen Slides 使用屏幕幻灯片ViewPager
查看>>
Displaying Card Flip Animations 显示卡片翻转动画
查看>>
Zooming a View 缩放视图
查看>>
Animating Layout Changes 动画布局的更改
查看>>
Controlling Your App’s Volume and Playback 控制应用程序的音量和播放
查看>>
Managing Audio Focus 管理音频焦点
查看>>
Dealing with Audio Output Hardware 处理音频输出硬件设备
查看>>
Monitoring the Battery Level and Charging State 监测电池电量和充电状态
查看>>
Determining and Monitoring the Docking State and Type 判断并监测设备的停驻状态与类型
查看>>
Determining and Monitoring the Connectivity Status 根据网络连接状况去省电
查看>>
Manipulating Broadcast Receivers On Demand 按需操控广播接收
查看>>