zoukankan      html  css  js  c++  java
  • 观察者模式和发布订阅模式(上)

    观察者模式

    定义:观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
    其中有两个定义需要明确,被观察者和观察者。通常来说,这两者是一对多的,也有多对多的情景。
    在网页开发中,被观察者通常是数据源,不论是内存数据,还是持久化数据,又或者是接口返回的数据,都可以作为被观察者。它一旦改变,就去改变依赖于它的节点。
    观察者有很多可能,针对于网页开发,我们常常认为dom节点是观察者,一旦节点的监视的数据源发生变化,节点也执行更新方法。当然不限于此,也有可能是一个事件,一次计数等等。
    接下来用js写一个简单的观察者模式的例子:

    // 发布类
    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();
    

    结果为:

    observer 1: test;
    observer 2: test;
    observer 3: test;
    observer 1: test;
    observer 3: test;
    

    这里简单定义了一个发布类和一个观察类,发布者维护一个观察者列表,每次数据变化后,依次通知所有在观察者列表里的观察者。
    代码很简单,可以执行在控制台或者node里跑一下。
    但是这样的耦合很深,观察者和发布者不能有其他的表现,很死板,我们可以继续抽象一下。
    先画个类图:
    类图
    借助于TypeScript,我们可以有如下的发布者和观察者定义。

    abstract class Observer {
        abstract update();
    }
    
    abstract class Subject {
        protected obList: ObserverList;
        abstract notify();
    }
    

    ObserverList则可以实现如下:

    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);
        }
    }
    

    跑一下测试代码:

    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方法了。
    观察者和被观察者,仍然耦合比较深,所以又有人提出来发布订阅模式,维护一个事件中心,来处理多个观察者和被观察者的关系,不让他们直接耦合在一起。下一篇对发布订阅做解析。

  • 相关阅读:
    JVM常用参数设置
    Jstat在分析java的内存GC时的应用
    jstack来分析linux服务器上Java应用服务性能异常
    linux 远程连接服务器ftp命令整理
    LR11中webservice协议的性能测试应用
    Windbg在.net性能问题排查hang情况的应用思路
    Windbg基本命令应用总结
    LR11直接对数据库访问操作方法在性能测试中的应用总结
    BenchmarkSQL v5.0测试达梦数据库
    SSH登录时间久,登录后报错:'abrt-cli status' timed out
  • 原文地址:https://www.cnblogs.com/liuyongjia/p/9404627.html
Copyright © 2011-2022 走看看