这篇文章主要使用类比的方法讲解observer模式,完整代码
mmdctjj/designPatternsgithub.com一、定义
先来看看它是怎么定义的
观察者模式是一个被称为目标的对象,将自己状态的变更自动通知给自己维护的一系列观察者的方法
单独从名字来看,这个模式的主体似乎是观察者,然而从定义中看主体却是观察者观察的目标,并且一个目标可以有多个观察者。
二、例子
举个例子,观察者模式就好像是我们自己的爱豆开通的粉丝模式(比如微博等)一样,爱豆(目标)会将自己的动态通知给所有关注(观察)自己的粉丝(观察者),这样所有的粉丝就会知道自己的爱豆做了啥
三、实现
要实现这个模式,须分析下这个模式中出现的对象
1.分析
上面的观察者(粉丝)模式中涉及到哪些对象?
显而易见的有:目标(爱豆)、观察者(粉丝)
2.实现
a.目标(爱豆)
定义中说过,目标(爱豆)是维护者一系列观察者(粉丝)的,所以在实现目标(爱豆)之前先实现ta的列表功能
// 首先列表是一个数组,每个元素都是一个观察者(粉丝)对象
class ObserverList {
// 初始化空列表
observerList=[];
}
// 给列表原型链上实现增加、查找、统计方法
ObserverList.prototype.Add = function(obj) {
this.observerList.push(obj);
};
ObserverList.prototype.Get = function(index) {
if (index > -1 && index < this.observerList.length) {
return this.observerList[index];
}
};
ObserverList.prototype.Count = function() {
return this.observerList.length;
};
接下来实现目标(爱豆)类
class Subject {
// 实例化一个空列表
observerList = new ObserverList();
}
// 目标原型链添加增加观察者功能
Subject.prototype.Add = function(obj) {
this.observerList.Add(obj);
};
// 目标原型链添加增加广播功能
Subject.prototype.Notify = function(news) {
let observerListCount = this.observerList.Count();
for (let i = 0; i < observerListCount; i++) {
// updata需要在观察者对象上定义
this.observerList.Get(i).Update(news);
}
};
b.观察者(粉丝)
观察者类更简单,只需要负责更新目标的变更就行
class Observer {
Update(){
// 具体需要在实例化中来定义
}
}
c.关联
接下来通过一个例子实现观察者模式
不过我们先要准备一个工具函数,将一个对象的属性可以扩展到另一个对象
// 扩展对象
function extend(obj, extension) {
for (const key in obj) {
extension[key] = obj[key];
}
}
我们使用一个input模拟目标(爱豆),使用多个input模拟观察者(粉丝)
具体看代码、
<button id="addObserver">关注这个爱豆</button>
<input id="subject" type="text" placeholder="哎,我是别人的爱豆" />
<div id="container"></div>
var addObserver = document.getElementById("addObserver"),
subject = document.getElementById("subject"),
container = document.getElementById("container"),
num = 0;
// 通过扩展函数,可以实例化一个目标,ta是个dom元素
extend(new Subject(), subject);
// 当目标失去聚焦时触发目标(爱豆)的广播功能
subject.onblur = new Function("subject.Notify(subject.value)");
// 每个点击事件都是添加一个观察者对象
addObserver.onclick = () => {
num += 1;
// 创建一个节点,ta代表一个观察者(粉丝)
var node = document.createElement("input");
node.type = "text";
node.placeholder = "我是你的粉丝" + num;
// 同样的道理,将观察者类(粉丝)的所有属性和方法扩展给每个观察者(粉丝)
extend(new Observer(), node);
// 目标(爱豆)的观察者(粉丝)+1
subject.Add(node);
// 这里就是我们具体自定义updata函数的地方
node.Update = value => {
node.value = value;
};
// 将节点添加到容器中
container.appendChild(node);
};
现在你可以通过点击关注按钮,创建很多观察者(粉丝),在目标(爱豆)输入框输入内容,当失去聚焦时,所有观察者(粉丝)都会一起更新目标的最新动态
写在后面
observer模式只是观察者模式的一种,除了observer模式还有发布/订阅者模式,它们都是一对多的设计理念,一个变化,所有的观察者都会接收到通知。
如果我的文章有错误,诚恳的希望您可以指出,我们一起进步