前端面试JS篇——观察者模式实例

673 阅读1分钟

观察者模式又称为发布-订阅模式,实际上这两者略有不同,不过广义上认为是同样的意思。指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 一个经典的例子是报社和订阅报纸的人。

<!-- html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>repl.it</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
  <div>
  <input id="text1"/>
  <button id="btn1"/>pub1 deliver</button>
  </div>

  <div>
  <input id="text2"/>
  <button id="btn2"/>pub2 deliver</button>
  </div>

  <div>
  <input id="text3"/>
  <button id="btn3"/>pub3 deliver</button>
  </div>

  <textarea id="sub1"></textarea>
  <textarea id="sub2"></textarea>

  </body>
  <script src="script.js"></script>
</html>
//发布者的构造函数
var Publish = function(name){  
  this.name = name;
  this.subscribers = [];  //订阅者列表,每个订阅者其实是一个处理得到信息的函数
}

//发布者的发布方法
Publish.prototype.deliver = function(news){
  this.subscribers.forEach(fn => fn(news)) //将信息发布给每个订阅者,fn代表订阅者
  return this  //链式编程
}

//观察者的订阅方法
Function.prototype.subscribe = function(publisher){  
  let alreadyIn = publisher.subscribers.some(
    subscriber => subscriber == this)
  if(!alreadyIn){
    publisher.subscribers.push(this)
  }
  return this
}

//取消订阅
Function.prototype.unsubscribe = function(publisher){
  publisher.subscribers.filter(subscriber=>subscriber!==this)
  return this
}

报社(发布者)的构造函数包括属性名字和他的所有订阅者(订阅报纸的人)数组,报社拥有发布信息的方法,即将news传递给每个订阅者fn,在这里要注意每个订阅者其实是一个处理从发布者获得信息的函数。所有的订阅者(fn)都有订阅的方法和取消订阅的方法。

window.onload = function(){
  let pub1 = new Publish("first publisher")
  let pub2 = new Publish("second publisher")
  let pub3 = new Publish("third publisher")

  let btn1 = document.getElementById("btn1")
  let btn2 = document.getElementById("btn2")
  let btn3 = document.getElementById("btn3")

  let sub1 = function(news){
    document.getElementById("sub1").innerHTML += news
  }
  let sub2 = function(news){
    document.getElementById("sub2").innerHTML += news
  }

  sub1.subscribe(pub1)
  sub2.subscribe(pub2).subscribe(pub3)

  btn1.addEventListener("click", ()=>pub1.deliver(document.getElementById("text1").value))
  btn2.addEventListener("click", ()=>pub2.deliver(document.getElementById("text2").value))
  btn3.addEventListener("click", ()=>pub3.deliver(document.getElementById("text3").value))
}

以上代码中,sub1订阅了pub1的内容,sub2订阅了pub2和pub3的内容,这两个订阅者会把发布者发布的内容分别输出在textarea中。例子的具体实现链接:repl.it/repls/Silly…