Typescript 觀察者模式(Observer)
阿新 • • 發佈:2020-12-08
請仔細閱讀下面程式碼,理解其中的設計理念。
observer.jpg觀察者模式
觀察者模式: 觀察者模式是定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。
實際場景
- 一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這些方面封裝在獨立的物件中使它們可以各自獨立地改變和複用。
- 一個物件的改變將導致其他一個或多個物件也發生改變,而不知道具體有多少物件將發生改變,可以降低物件之間的耦合度。
- 一個物件必須通知其他物件,而並不知道這些物件是誰。
- 需要在系統中建立一個觸發鏈,A物件的行為將影響B物件,B物件的行為將影響C物件……,可以使用觀察者模式建立一種鏈式觸發機制。
觀察者模式的結構
- Client: 客戶端
- Subject: 通知者
- Observer: 觀察者
觀察者模式的例子
這裡我們使用vue中的觀察者模式作為例子(為了簡潔,省略部分程式碼)
其中的資料走向如下圖所示。
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 = getter ? getter.