模式学习⑧--观察者模式

var publisher = {

        // 一个由数组组成的集合
        subscribers : {
            any : []// 事件类型: 订阅者(subsribes)
        },

        // 将订阅者加入数组 // subscribers : { any : [fn], weekly : [fn], monthly : [fn]}
        subscribe : function(fn, type){
            type = type || 'any';
            if(typeof this.subscribers[type] === "undefined"){
                console.log("this ::",this);
                this.subscribers[type] = [];
            }
            this.subscribers[type].push(fn); //any ->  [fn] /  weekly -> [fn] / monthly -> [fn]
            // console.log("this.subscribers[type]     ",this.subscribers["any"]);
            // console.log("this.subscribers[type]     ",this.subscribers["monthly"]);
        },

        // 从数组中删除订阅者
        unsubscribe : function(fn, type){
            this.visitSubscribers('unsubscribe', fn, type);
        },

        // 遍历订阅者并调用它们订阅时提供的方法
        publish : function(publication, type){
            this.visitSubscribers('publish', publication, type);
        },
        visitSubscribers : function(action, arg, type){ // action = 'publish' ,arg = publication = "big news today"
            var pubtype = type || 'any',
                subscribers = this.subscribers[pubtype],// subscribe得到的数组[fn]
                i,
                max = subscribers.length;
            for(i = 0; i < max; i++){
                if(action === 'publish'){
                    // console.log("arg:", arg)
                    subscribers[i](arg); // 执行 fn()
                }else{  
                    if(subscribers[i] === arg){
                        subscribers.splice(i, 1);
                    }
                }
            }
        }
    };

    function makePublisher(o){
        var i;
        for(i in publisher){
            if(publisher.hasOwnProperty(i) && typeof publisher[i] === "function"){
                o[i] = publisher[i];
            }
        }
        o.subscribers = {any : []};
    }

    // 实现paper对象,它所能做的就是发布日报和月刊
    var paper = {
        daily : function(){
            this.publish("big news today");
        },
        weekly : function(){
            this.publish("big news in a week", 'weekly');
        },
        monthly : function(){
            this.publish("interesting analysis", "monthly");
        }
    };

    // 将paper对象变成发布者:
    makePublisher(paper);

    // 订阅者对象joe
    var joe = {
        drinkCoffee : function(paper){
            console.log("Just read " + paper);
        },
        dinner : function(weekly){
            console.log("Just read " + weekly);
        },
        sundayPreNap : function(monthly){
            console.log("About to fall asleep reading this " + monthly);
        }
    };

    // 现在,paper注册joe
    paper.subscribe(joe.drinkCoffee);
    paper.subscribe(joe.dinner, 'weekly');
    paper.subscribe(joe.sundayPreNap, 'monthly');

    paper.daily();
    paper.weekly();
    paper.monthly();
    paper.daily();
    paper.daily();
    paper.monthly();

    makePublisher(joe);
    joe.tweet = function(msg){
        this.publish(msg);
    };

    paper.readTweets = function(tweet){
        console.log("Call big meeting! Someone " + tweet);
    };
    joe.subscribe(paper.readTweets);

    joe.tweet("hates the paper today");
   joe.tweet("loves the paper today");

说明:

  1. 将发布publish作为单独的Object,再借用Makepublisher()方法, 可以使得paper, joe, xx , oo 都能成为发布者。

  2. subscribers 在这里是类似于 { any : [fn], weekly : [fn], monthly : [fn]} 这样的object. 里面的 any weekly monthly 都是type类型。(any是默认的)

  3. A - MakePublisher(xx), 让xx成为发布者

    B - xx.subscribe(oo); oo 可以是另一个观察者的方法-既是订阅

     C - 发布:调用publish()方法

  4. 其中的访问订阅者visitSubscribers ,用来 -发布/删除- 订阅者  

    publication 是发布的内容,subscribers = this.subscribers[pubtype] - 获取发布者的type对应的 订阅者要执行的函数 相当于 1 中的[fn],  subScribers[i](arg) ,但其实这里的arg又是引用的发布者的内容, 就是根据发布的类型执行了订阅者本身的函数(参数是发布的内容)。 

  5. A 可以给 B发布,B也可以给A发布。

原文地址:https://www.cnblogs.com/chuyu/p/3499569.html