一、什么是Observer(观察者)模式
Observer(观察者)是一种设计模式,其中,一个对象(subject)维持一系列依赖于它(观察者)的对象,将有关状态的任何变更自动通知给他们。观察者模式是一个被称为目标的对象,将自己状态的变更自动通知给自己维护的一系列观察者的方法。
二、具体实现
我们实现Observer模式需要使用到以下组件:
- Subject(目标):维护一系列的观察者,方便添加或者删除观察者。
- Observer(观察者):为那些在目标状态发生改变时需要获得通知的对象提供一个更新接口。
- ConcreteSubject(具体目标):状态发生改变时,向Observer发出通知,储存ConcreteObserver的状态。
- ConcreteObserver(具体观察者):储存一个指向ConcreteSubject的引用,实现Observer的更新接口,以使自身状态与目标状态保持一致。
首先,我们来模拟一个目标可能拥有的一系列依赖Observer:
// 用来保存所有的observer
function ObserverList() {
this.observerlist = [];
}
// 添加一个observer
ObserverList.prototype.Add = function (obj) {
return this.observerlist.push(obj);
};
// 清空所有列表
ObserverList.prototype.Empty = function () {
this.observerlist = [];
};
// 查看当前观察者的个数
ObserverList.prototype.Count = function () {
return this.observerlist.length;
};
// 根据索引获得对应的observer
ObserverList.prototype.Get = function (index) {
if (index > -1 && index < this.observerlist.length) {
return this.observerlist[index];
}
};
// 在头部或者尾部插入一个obj
ObserverList.prototype.Inset = function (obj, index) {
let pointer = -1;
if (index === 0) {
this.observerlist.unshift(obj);
} else if (index === this.observerlist.length) {
this.observerlist.push(obj);
pointer = index;
}
return pointer;
};
// 传入对象找到对应的索引
ObserverList.prototype.IndexOf = function (obj, startIndex) {
let i = startIndex,
pointer = -1;
while (i < this.observerlist.length) {
if (this.observerlist[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();
}
};
// 使用extension 扩展对象
function extend(obj, extension) {
for (let key in obj) {
extension[key] = obj[key];
}
}
复制代码
接下来,让我们模拟目标(subject)和在观察者列表上添加、删除或者通知观察者的能力
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) {
let observerCount = this.observers.Count();
for (let i = 0; i < observerCount; i++) {
this.observers.Get(i).Update(context);
}
};
复制代码
然后定义一个框架来创建新的Observer。Update可根据业务功能自行定义。
function Observer () {
this.Update = function(context) {
console.log('我要更新了', context);
}
}
复制代码
至此,一个简易的Observer模式就已经写好啦,让我们结合业务,来使用一下它吧~
我们利用Observer模式来实现这样一个功能,控制多选框的全选或者取消全选,并做出相应的通知。
通过点击按钮来增加新的Observer,当全选按钮(subject)更新时,我们通知相应的Observer来做出更新。
首先,完成DOM结构的建立
<button id="addNewObserver">Add New Ovserver checkbox</button>
<br>
全选/取消全选<input type="checkbox" id="mainCheckbox" />
<div id="observersContasiner"></div>
复制代码
然后,将进行主要逻辑的书写
// 获取对应的DOM节点对象
let controlCheckbox = document.getElementById("mainCheckbox");
let addBtn = document.getElementById('addNewObserver');
let container = document.getElementById('observersContasiner');
// 利用Subject 扩展controlCheckbox
extend(new Subject(), controlCheckbox);
// 点击checkbox 会触发通知到观察者上
controlCheckbox["onclick"] =function () {
controlCheckbox.Notify(controlCheckbox.checked)
};
// 点击按钮,增加一个Observer
addBtn["onclick"] = AddNewObserver;
// 具体观察者 Concrete Observer
function AddNewObserver () {
// 创建需要添加的新的checkbox
let check = document.createElement("input");
check.type = 'checkbox';
// 利用Observer 类 扩展checkbox
extend(new Observer(), check);
// 重写自定义更新行为
check.Update = function(value){
console.log('全选按钮更新了----');
check.checked = value;
}
// 为主subject 的观察者列表添加新的观察者
controlCheckbox.AddObserver(check);
// 将观察者附件到容器上
container.appendChild(check);
}
复制代码
到此,我们已经完成了上述功能,下面附上完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Observer观察者模式</title>
</head>
<body>
<button id="addNewObserver">Add New Ovserver checkbox</button>
<br>
全选/取消全选<input type="checkbox" id="mainCheckbox" />
<div id="observersContasiner"></div>
<script>
// 用来保存所有的observer
function ObserverList() {
this.observerlist = [];
}
// 添加一个observer
ObserverList.prototype.Add = function (obj) {
return this.observerlist.push(obj);
};
// 清空所有列表
ObserverList.prototype.Empty = function () {
this.observerlist = [];
};
// 查看当前观察者的个数
ObserverList.prototype.Count = function () {
return this.observerlist.length;
};
// 根据索引获得对应的observer
ObserverList.prototype.Get = function (index) {
if (index > -1 && index < this.observerlist.length) {
return this.observerlist[index];
}
};
// 在头部或者尾部插入一个obj
ObserverList.prototype.Inset = function (obj, index) {
let pointer = -1;
if (index === 0) {
this.observerlist.unshift(obj);
} else if (index === this.observerlist.length) {
this.observerlist.push(obj);
pointer = index;
}
return pointer;
};
// 传入对象找到对应的索引
ObserverList.prototype.IndexOf = function (obj, startIndex) {
let i = startIndex,
pointer = -1;
while (i < this.observerlist.length) {
if (this.observerlist[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();
}
};
// 使用extension 扩展对象
function extend(obj, extension) {
for (let key in obj) {
extension[key] = obj[key];
}
}
/**
* @description: 模拟目标subject 和在观察者列表上添加、删除或者通知观察者的能力
* @param {*}
* @return {*}
*/
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) {
let observerCount = this.observers.Count();
for (let i = 0; i < observerCount; i++) {
this.observers.Get(i).Update(context);
}
};
// The Observer
function Observer () {
this.Update = function(context) {
console.log('我要更新了', context);
}
}
</script>
<script>
// 获取对应的DOM节点对象
let controlCheckbox = document.getElementById("mainCheckbox");
let addBtn = document.getElementById('addNewObserver');
let container = document.getElementById('observersContasiner');
// 利用Subject 扩展controlCheckbox
extend(new Subject(), controlCheckbox);
// 点击checkbox 会触发通知到观察者上
controlCheckbox["onclick"] =function () {
controlCheckbox.Notify(controlCheckbox.checked)
};
// 点击按钮,增加一个Observer
addBtn["onclick"] = AddNewObserver;
// 具体观察者 Concrete Observer
function AddNewObserver () {
// 创建需要添加的新的checkbox
let check = document.createElement("input");
check.type = 'checkbox';
// 利用Observer 类 扩展checkbox
extend(new Observer(), check);
// 重写自定义更新行为
check.Update = function(value){
console.log('全选按钮更新了----');
check.checked = value;
}
// 为主subject 的观察者列表添加新的观察者
controlCheckbox.AddObserver(check);
// 将观察者附件到容器上
container.appendChild(check);
}
</script>
</body>
</html>
复制代码
最后,如果发现有任何问题,欢迎指正~~
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END