觀察者模式和發佈訂閱模式(上)

觀察者模式

定義:觀察者模式(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

相關文章
相關標籤/搜索