zoukankan      html  css  js  c++  java
  • js实现观察者模式

    基本概念介绍

    观察者(observer) 模式广泛用于客户端Javascript编程中。所有的浏览器事件都是该模式的例子。它的另一个名字也称为自定义事件(custom events),与那些由浏览器触发的事件相比,自定义事件表示是由你编程实现的事件。此外,该模式的另一个别名也称为订阅/发布(subscriber/publisher)模式。

    设计该模式背后的主要动力是促进形成松散耦合。在这种模式中,并不是一个对象调用另一个对象的方法,而是一个对象订阅另一个对象的特定活动并在状态改变后获得通知。订阅者也称为观察者,而补观察的对象称为发布者或主题。当发生了一个重要的事件时,发布者将会通知(调用)所有订阅者并且可能经常以事件对象的形式传递消息。

    示例:杂志订阅

    假设有一个发布者paper,它每天出版报纸及月刊杂志。订阅者joe将被通知任何时候所发生的新闻。

    该paper对象需要一个subscribers(topics )属性,该属性是一个存储所有订阅者的数组。订阅行为只是将其加入到这个数组中。当一个事件发生时,paper将会循环遍历订阅者列表并通知它们。通知意味着调用订阅者对象的某个方法。故当用户订阅信息时,该订阅者需要向paper的subscribe()提供它的其中一个方法。

    paper也提供了unsubscribe()方法,该方法表示从订阅者数组(即subscribers属性)中删除订阅者。paper最后一个重要的方法是publish(),它会调用这些订阅者的方法,总而言之,发布者对象paper需要具有以下这些成员:

    1.subscribers 一个数组 2.subscribe() 将订阅者添加到subscribers数组中 3.unsubscribe() 从subscribers数组中删除订阅者 4.publish() 循环遍历subscribers数组中的每一个元素,并且调用他们注册时所提供的方法

    所有这三种方法都需要一个topic参数,因为发布者可能触发多个事件(比如同时发布一本杂志和一份报纸)而用户可能仅选择订阅其中一种,而不是另外一种。

    由于这些成员对于任何发布者对象都是通用的,故将它们作为独立对象的一个部分来实现是很有意义的。那样我们可将其复制到任何对象中,并将任意给定对象变成一个发布者。

    JS里对观察者模式的实现是通过回调来实现的,我们来先定义一个pubsub对象,其内部包含了3个方法:订阅、退订、发布。

    var pubsub = {};
    (function (q) {
    
        var topics = {}, // 回调函数存放的数组
            subUid = -1;
        // 发布方法
        q.publish = function (topic, args) {
    
            if (!topics[topic]) {
                return false;
            }
    
            setTimeout(function () {
                var subscribers = topics[topic],
                    len = subscribers ? subscribers.length : 0;
    
                while (len--) {
                    subscribers[len].func(topic, args);
                }
            }, 0);
    
            return true;
    
        };
        //订阅方法
        q.subscribe = function (topic, func) {
    
            if (!topics[topic]) {
                topics[topic] = [];
            }
    
            var token = (++subUid).toString();
            topics[topic].push({
                token: token,
                func: func
            });
            return token;
        };
        //退订方法
        q.unsubscribe = function (token) {
            for (var m in topics) {
                if (topics[m]) {
                    for (var i = 0, j = topics[m].length; i < j; i++) {
                        if (topics[m][i].token === token) {
                            topics[m].splice(i, 1);
                            return token;
                        }
                    }
                }
            }
            return false;
        };
    } (pubsub));

    使用方式如下:

    //来,订阅一个
    pubsub.subscribe('example1', function (topics, data) {
        console.log(topics + ": " + data);
    });
    
    //发布通知
    pubsub.publish('example1', 'hello world!');
    pubsub.publish('example1', ['test', 'a', 'b', 'c']);
    pubsub.publish('example1', [{ 'color': 'blue' }, { 'text': 'hello'}]);

    试试多个订阅者订阅同个主题:

    //来,订阅一个
    pubsub.subscribe('example1', function (topics, data) {
        console.log(topics + ": " + data);
    });
    //来,再订阅一个
    pubsub.subscribe('example1', function (topics, data) {
        console.log(topics + "******* " + data);
    });
    
    //发布通知
    pubsub.publish('example1', 'hello world!');

    输出:

    example1***** hello world!
    example1: hello world!

    参考:http://www.2cto.com/kf/201210/163500.html

    http://www.cnblogs.com/TomXu/archive/2012/03/02/2355128.html

  • 相关阅读:
    TDateTime 的相关用法
    Delphi 2005 之后的版本如何装组件
    (收藏)《博客园精华集》分类索引
    用 IIS 7、ARR 與 Velocity 建设高性能的大型网站
    异常处理准则
    Linq之动态排序(字符传入)
    用存储过程构造一个虚拟日期表发现的趣事
    Linq to SQL 加注Data Annotation在 Asp.Net MVC2中的应用
    .net framework加密方法
    SQL Server到Oracle连接服务器
  • 原文地址:https://www.cnblogs.com/winkey4986/p/4884484.html
Copyright © 2011-2022 走看看