设计模式

设计模式——观察者模式与订阅-发布模式

2018-11-13  本文已影响12人  BULL_DEBUG

首先,个人觉得观察者模式和订阅-发布模式是有区别的(一些文章会认为观察者模式即为订阅-发布模式),然后分别介绍一下这两种模式以及两种模式的区别。

先列出两者区别

观察者模式

观察者模式 在软件设计中是一个对象,维护一个依赖列表,当任何状态发生改变自动通知它们。

比较概念的解释是,目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。

比如有个“天气中心”的具体目标A,专门监听天气变化,而有个显示天气的界面的观察者B,B就把自己注册到A里,当A触发天气变化,就调度B的更新方法,并带上自己的上下文。

image

订阅-发布模式

在发布-订阅模式,消息的发送方,叫做发布者(publishers),消息不会直接发送给特定的接收者,叫做订阅者。

意思就是发布者和订阅者不知道对方的存在。需要一个第三方组件,叫做信息中介,它将订阅者和发布者串联起来,它过滤和分配所有输入的消息。换句话说,发布-订阅模式用来处理不同系统组件的信息交流,即使这些组件不知道对方的存在。

比较概念的解释是,订阅者把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心(顺带上下文),由调度中心统一调度订阅者注册到调度中心的处理代码。

比如有个界面是实时显示天气,它就订阅天气事件(注册到调度中心,包括处理程序),当天气变化时(定时获取数据),就作为发布者发布天气信息到调度中心,调度中心就调度订阅者的天气处理程序。

image

附录

观察者模式实现代码(JavaScript版):

  <script>
        /*
            观察者模式 
        */ 
        // 观察者列表 定义一个 ObserverList 类方便管理多个数据
        function ObserverList() {
            this.observerList = [];
        }
         // 添加到观察者列表
        ObserverList.prototype.add = function(obj) {
            return this.observerList.push(obj);
        }
        // 观察者列表长度
        ObserverList.prototype.count = function () {
            return this.observerList.length;
        }
         // 获取当前观察者
        ObserverList.prototype.get = function (index) {
            if (index > -1 && index < this.observerList.length) {
                return this.observerList[ index ];
            }
        }
         // 检测是否在列表中
        ObserverList.prototype.indexOf = function(obj, startIndex) {
            var i = startIndex;
            var len = this.observerList.length;
            while (i < len) {
                if ( this.observerList[i] === obj) {
                    return i;
                }
                i ++;
            }
            return -1;
        }
        // 取消订阅
        ObserverList.prototype.removeAt = function (index) {
            this.observerList.splice(index, 1);
        }

        // 被观察目标
        function Subject () {
            this.observers = new ObserverList();
        }
        Subject.prototype.addObserver = function (observer) {
            this.observers.add(observer);
        }
        Subject.prototype.removeObserver = function (observer) {
            this.observers.removeAt(this.observers.indexOf(observer, 0));
        }
        Subject.prototype.notify = function (context) {
            var observerCount = this.observers.count();
            for (var i = 0; i < observerCount; i++) {
                this.observers.get(i).update(context) 
            }
        }

        // 定义一个 Observer 类作为观察者
        function Observer(id) {
            this.id = id;
        }
        Observer.prototype.update = function(data) {
            console.log(data + '_' + this.id);
            var content = document.getElementById("content");

            content.innerHTML = '<div>' + data + '_' + this.id + '</div>'
        }
        var data = new Subject();
        // 让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能自动更新自己。
       
        var abserver1 = new Observer(1); // 观察者1
        var abserver2 = new Observer(2); // 观察者2
        var abserver3 = new Observer(3); // 观察者3
        data.addObserver(abserver1);
        data.addObserver(abserver2);
        data.addObserver(abserver3);
        data.removeObserver(abserver3);
        data.notify('ccccc');
    </script> 

订阅-发布模式

 <script>
        // 定义DataHub作为发布者
        function DataHub() {};

        DataHub.prototype.notify = function(url, callback) {
            callback(url);
        }

        // DownloadManager类作为事件通道
        function DownloadManager() {
            this.events = {};
            this.uId = -1;
        }
        DownloadManager.prototype.publish = function(eventType, url) {
            if (!this.events[eventType]) {
                return false;
            }
            var subscribers = this.events[eventType],
            count = subscribers ? subscribers.length : 0;
            while (count --) {
                var subscriber = subscribers[count];
                subscriber.handler(eventType, subscriber.taskId, url);
            }
        } 
        DownloadManager.prototype.subscribe = function(eventType, handler) {
            if (!this.events[eventType]) {
                this.events[eventType] = [];
            }
            var taskId = (++this.uId).toString();
            this.events[eventType].push({
                taskId: taskId,
                handler: handler
            })
            return taskId;
        }
        // 创建一个数据中心
        var dataHub = new DataHub();
        // 创建一个下载事件管理器
        var downloadManager = new DownloadManager();
        // 创建一个下载器
        var dataLoader = function(eventType, taskId, url) {
            console.log('Task ' + taskId + ' load data from ' + url);
        }
        // 用户来请求数据了
        var downloadTask1 = downloadManager.subscribe('dataReady', dataLoader);
        var downloadTask2 = downloadManager.subscribe('dataReady2', dataLoader);
        console.log(downloadTask1);
        console.log(downloadTask2);
        // 数据打包完成了
       
        dataHub.notify('http://somedomain.someaddress', function(url) {
            downloadManager.publish('dataReady', url);
            downloadManager.publish('dataReady2', url)
        });
      
    </script>
上一篇 下一篇

猜你喜欢

热点阅读