定義:觀察者模式(Observer Pattern):定義對象間的一種一對多依賴關係,使得每當一個對象狀態發生改變時,其相關依賴對象皆獲得通知並被自動更新。
其中有兩個定義須要明確,被觀察者和觀察者。一般來講,這二者是一對多的,也有多對多的情景。
在網頁開發中,被觀察者一般是數據源,不管是內存數據,仍是持久化數據,又或者是接口返回的數據,均可以做爲被觀察者。它一旦改變,就去改變依賴於它的節點。
觀察者有不少可能,針對於網頁開發,咱們經常認爲dom節點是觀察者,一旦節點的監視的數據源發生變化,節點也執行更新方法。固然不限於此,也有多是一個事件,一次計數等等。
接下來用js寫一個簡單的觀察者模式的例子:javascript
// 發佈類 class Subject { constructor (data) { this.obList = []; this.data = data; } add (ob) { if (arguments.length >= 1) { Array.from(arguments).forEach(item => this.obList.push(item)); } } remove (ob) { let i = this.obList.findIndex(ele => ele === ob); if (i >= 0) { this.obList.splice(i, 1); } } notify () { this.obList.forEach((item) => { item.update(this.data); }) } } // 觀察者類 class Observer { constructor (id) { this.id = id; } update (data) { console.log('observer ' + this.id + ': ' + data + ';'); } } function test() { let sub = new Subject('test'); let ob1 = new Observer(1); let ob2 = new Observer(2); let ob3 = new Observer(3); sub.add(ob1, ob2, ob3); sub.notify(); sub.remove(ob2); sub.notify(); } test();
結果爲:java
observer 1: test; observer 2: test; observer 3: test; observer 1: test; observer 3: test;
這裏簡單定義了一個發佈類和一個觀察類,發佈者維護一個觀察者列表,每次數據變化後,依次通知全部在觀察者列表裏的觀察者。
代碼很簡單,能夠執行在控制檯或者node裏跑一下。
可是這樣的耦合很深,觀察者和發佈者不能有其餘的表現,很死板,咱們能夠繼續抽象一下。
先畫個類圖:
藉助於TypeScript,咱們能夠有以下的發佈者和觀察者定義。node
abstract class Observer { abstract update(); } abstract class Subject { protected obList: ObserverList; abstract notify(); }
ObserverList則能夠實現以下:dom
class ObserverList { private list: Array<Observer>; constructor () { this.list = []; } add (ob: Observer) { this.list.push(ob); } remove (ob: Observer) { if (this.list.indexOf(ob) > -1) { this.list.splice(this.list.indexOf(ob), 1); } } empty () { this.list = []; } public each () { this.list.forEach(item => { item.update(); }) } }
接下來實現兩個實體類:測試
// 實體發佈類 class ConcreteSubject extends Subject { protected obList = new ObserverList(); private _data: string; constructor (defaultData: string) { super(); this._data = defaultData; } set data (newVaule) { this._data = newVaule; } get data () { return this._data; } add (ob: Observer) { this.obList.add(ob); } remove (ob: Observer) { this.obList.remove(ob); } notify () { this.obList.each() } } // 能夠指定發佈者的觀察者類 class ConcreteObserver extends Observer { readonly _id; private sub; constructor (id, sub) { super(); this._id = id; this.sub = sub; } get id () { return this._id; } update () { console.log('concrete observer ' + this.id + ': ' + this.sub.data); } }
跑一下測試代碼:this
let sub = new ConcreteSubject('test'); let ob1 = new ConcreteObserver(1, sub); let ob2 = new ConcreteObserver(2, sub); let ob3 = new ConcreteObserver(3, sub); sub.add(ob1) sub.add(ob2) sub.add(ob3) sub.notify();
上面的發佈類,使用add、remove等方法來處理觀察者列表,經過notify方法,則去通知觀察者們,能夠去執行update方法了。
觀察者和被觀察者,仍然耦合比較深,因此又有人提出來發佈訂閱模式,維護一個事件中心,來處理多個觀察者和被觀察者的關係,不讓他們直接耦合在一塊兒。下一篇對發佈訂閱作解析。code