请仔细阅读下面代码,理解其中的设计理念。
![](http://upload-images.jianshu.io/upload_images/3133116-73ed36f713a29150.jpg?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)
observer.jpg
观察者模式
观察者模式: 观察者模式是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
实际场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
观察者模式的结构
- Client: 客户端
- Subject: 通知者
- Observer: 观察者
观察者模式的例子
这里我们使用vue中的观察者模式作为例子(为了简洁,省略部分代码)
其中的数据走向如下图所示。
![](http://upload-images.jianshu.io/upload_images/3133116-744d06eb9d0494b1.png?imageMogr2/auto-orient/strip|imageView2/2/w/901/format/webp)
Observer.png
- vue中的变量会改造成observer对象,运用观察者模式来实现双向绑定等操作。
- observer在观察者模式中相当于client
/* observer.ts */
import { defineReactive } from './define-reactive';
import Dep from './dep';
function def(obj: Object, key: string, val: any) {
Object.defineProperty(obj, key, {
value: val,
enumerable: false,
writable: true,
configurable: true
})
}
/**
* 重写设置__ob__对象
* 增加观察者模式
*/
export default class Observer {
value: any;
dep: Dep;
// 这里只演示值为对象情况
constructor (value: Object) {
this.value = value;
this.dep = new Dep();
def(value, '__ob__', this);
this.walk(value)
}
walk (obj: Object) {
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
}
/* define-reactive.ts */
import Dep from './dep';
/**
* 将可配置的对象设置成__ob__对象
* get方法和set方法添加观察者模式
*/
export function defineReactive (obj: Object, key: string, val?: any,) {
const dep = new Dep();
// 只设置可配置的对象
const property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
return
}
const getter = property && property.get;
if (!getter && arguments.length === 2) {
val = obj[key]
}
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val;
/**
* 如果在某一个watcher的上下文调用到了这个对象
* 那么这个watcher订阅这个对象改变的消息
* 这个对象改变的时候watcher执行更新函数
*/
if (Dep.target) {
dep.depend();
}
return value
},
set: function reactiveSetter (newVal) {
const value