[观察者模式: Observer]

199 阅读3分钟

# 观察者模式:Observer

这个是一个学习笔记,嗯,相信很多同学和我一样,并没有真正搞明白观察者模式发布订阅模式到底有什么区别。于是在网上各种搜索资料,但其实解释并不是很清楚,各种看书找资料,坚持把各种观察者模式的用例都放在这里,方便回顾和学习。

站在巨人的肩膀上学习观察者模式。观察者模式的各种使用场景会在持续更新中。

## 概念

  • 主题: Subject // 维护一些列的观察者,方便添加或者删除观察者。
  • 观察者: Observer // 提供更新接口
  • 具体的目标: ConcreteSubject // 状态发生改变的时候,向观察者发发出通知
  • 具体的观察者: ConcreteObserver // 存储一个 ConcreteSubject 的引用。

## 图理解

## 文字理解

观察者模式: Observer 是通过一个对象(或者主题 Subject, 或者成为目标)来来维持一些列观察者的对象。当主题 Subject 有变化的时候,会通知观察者。

一个主题(或者目标)是通过类似于广播的形式来告诉观察者有关的通知。当不希望特定的观察者继续获取通知的时候,我们可将通过Subject将其从观察者列表中移除。

也就是说观察者模式包含了一个观察者列表,所有的观察者全部放在这个这个列表中,当某个列表不在需要观察服务后,可以从列表中移除。

一个或者多个观察者对目标感兴趣,他们通过将自己依附在目标对象上以便注册所感兴趣的内容。目标状态发生了改变并且观察者可能对这些感兴趣,就会发送一个通知消息,调用每个观察者的更新方法。当观察者不在对目标感兴趣时,他们可以简单的将自己从中分离。

<!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>Observer</title>
  </head>
  <body>
    <button id="addNewObserver">Add New Observer checkbox</button>
    <input type="checkbox" id="mainCheckbox" />
    <div id="observersContainer"></div>
  </body>
  <script src="./script.js"></script>
</html>
function ObserverList() {
  this.observerList = []
}

ObserverList.prototype.Add = function (obj) {
  return this.observerList.push(obj)
}

ObserverList.prototype.Empty = function () {
  this.observerList = []
}

ObserverList.prototype.Count = function () {
  return this.observerList.length;
}

ObserverList.prototype.Get = function (index) {
  if (index > -1 && index < this.observerList.length) {
    return this.observerList[index]
  }
}

ObserverList.prototype.Insert = function (obj, index) {
  var point = -1;

  if (index === 0) {
    this.observerList.unshift(obj)
    pointer = index
  } else if (index === this.observerList.length) {
    this.observerList.push(obj)
    pointer = index
  }
  return pointer
}

ObserverList.prototype.IndexOf = function (obj, startIndex) {
  var i = startIndex, pointer = -1;
  while (i < this.observerList.length) {
    if (this.observerList.length[i] === obj) {
      pointer = i
    }
    i++
  }
  return pointer
}

ObserverList.prototype.RemoveIndexAt = function (index) {
  if (index === 0) {
    this.observerList.shift()
  } else if (index === this.observerList.length - 1) {
    this.observerList.pop()
  }
}

function extend(obj, extension) {
  for (var key in obj) {
    extension[key] = obj[key]
  }
}

function Subject() {
  this.observers = new ObserverList();
}

Subject.prototype.AddObserver = function (observer) {
  this.observers.Add(observer)
}

Subject.prototype.removeObserver = function (observer) {
  this.observers.RemoveIndexAt(this.observers.IndexOf(observer, 0))
}

Subject.prototype.Notify = function (context) {
  var observerCount = this.observers.Count()
  for (var i = 0; i < observerCount; i++) {
    this.observers.Get(i).Update(context)
  }
}

function Observer() {
  // 需要被重写
  this.Update = function () {
    // some code
  }
}

var controlCheckbox = document.getElementById('mainCheckbox'),
  addBtn = document.getElementById('addNewObserver'),
  container = document.getElementById('observersContainer'),
  notify = document.getElementById('notify')

// controlCheckbox 上扩展主题的方法 AddObserver,removeObserver, Notify
extend(new Subject(), controlCheckbox)

controlCheckbox["onclick"] = new Function("controlCheckbox.Notify(controlCheckbox.checked)")
addBtn["onclick"] = AddNewObserver;

function AddNewObserver() {
  var check = document.createElement("input")
  check.type = "checkbox"
  // check 上添加 Update 属性
  extend(new Observer(), check)
  
  check.Update = function (value) {
    debugger
    this.checked = value;
  }
  
  controlCheckbox.AddObserver(check)

  container.appendChild(check)
}

在这个例子中,主题 Subject 通过 notify 方法通知所有的观察者更新数据。

  • 主题 Subject
  • 具体主题是 controlCheckbox
  • 观察这是 Observer,通过 extends 给 check 赋能 Update 方法。
  • 具体的观察者: 每一个 check

## 观察者模式与发布订阅模式的区别

观察者模式是通过主题直接就通知了观察者。中间没有多余的层级关系。但是发布订阅模式不同,发布订阅通知不是直接关系,存在一个中间层。发布订阅会在后面的继续文章深入探索。因为发布订阅和观察模式,在前端太常用了!

## 参考

  1. [JavaScript 设计模式](Addy Osmani著作,徐涛 翻译)