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