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

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

      思路:发布者对象需要一个数组类型的属性,以存储所有的订阅者。订阅(即注册)行为就是将新的订阅者加入到这个数组中去,则注销即是从这个数组中删除某个订阅者。此外,发布消息,就是循环遍历订阅者列表并通知他们。

      

      这里我的大体思路是对的,但是在发布者之外定义了一个新的类即订阅者。在订阅者中定义了一个方法getNews以便在发布者发布消息时调用该方法。然后面试官说这样太麻烦了,万一订阅者没有这个方法呢?然后我不是很懂……于是在发布消息时直接传递了参数:obj.news = msg; 然后面试官说这样不是更麻烦了吗?这样的话如果订阅者没有news这个属性怎么办?还得判断订阅者是否有news这个属性,没有的话就会出现undifined的报错。然后我就不知道该怎么做了……然后面试官为人特别nice,告诉我说可以用继承,或者是在注册时候就传入一个function。

    下来后上网查相关,注意点如下:

      1. 发送消息即通知,意味着调用订阅者对象的某个方法。故当用户订阅信息时,该订阅者需要向paper的subscribe()提供它的其中一个方法。--------这应该就是面试官所说的注册时候就传入一个方法。

      2. 发布对象paper需要具有以下成员:

        a、 subscribers:一个数组,存储订阅者

        b、 subscribe():注册/订阅,将订阅者添加到subscribers数组中

        c、 unsubscribe(): 取消订阅。从subscribers数组中删除订阅者

        d、 publish() 循环遍历subscribers数组中的每一个元素,并且调用他们注册时所提供的方法

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

      3、

    参考《JavaScript模式》一书,使用字面量。实现代码如下:

     1         //由于这些成员对于任何发布者对象都是通用的,故将它们作为独立对象的一个部分来实现是很有意义的。那样我们可将其复制到任何对象中,并将任意给定对象变成一个发布者。
     2 
     3         //如下实现一个通用发布者
     4 
     5         //定义发布者对象...{}是定义一个对象
     6         var publisher = {
     7             subscribers: {
     8                 any: []         //event type: subscribers
     9             },
    10             subscribe: function(fn,type){
    11                 type = type || 'any';
    12                 if(typeof this.subscribers[type] === "undefined"){
    13                     this.subscribers[type] = [];
    14                 }
    15                 this.subscribers[type].push(fn);
    16             },
    17             unsubscribe: function(fn,type){
    18                 this.visitSubscribers('unsubscribe', fn, type);
    19             },
    20             publish: function(publication, type){
    21                 this.visitSubscribers('publish',publication,type);
    22             },
    23             visitSubscribers:function(action,arg,type){
    24                 var pubtype = type ||'any',
    25                     subscribers = this.subscribers[pubtype],
    26                     i,
    27                     max = subscribers.length;
    28                 for(i=0;i<max;i++){
    29                     if(action == "publish"){
    30                         subscribers[i](arg);
    31                     } else {
    32                         if(subscribers[i] === arg){
    33                             subscribers.splice(i,1);
    34                         }
    35                     }
    36                 }
    37             }
    38         };
    39         //定义一个函数makePublisher(),它接受一个对象作为对象,通过把上述通用发布者的方法复制到该对象中,从而将其转换为一个发布者
    40         function makePublisher(o){
    41             var i;
    42             for(i in publisher) {
    43                 if(publisher.hasOwnProperty(i) && typeof publisher[i] === "function"){
    44                     o[i] = publisher[i];
    45                 }
    46             }
    47             o.subscribers = {any: []};
    48         }
    49         //实现paper对象
    50         var paper = {
    51             daily: function(){
    52                 this.publish("big news today");
    53             },
    54             monthly: function(){
    55                 this.publish("interesting analysis","monthly");
    56             }
    57         };
    58         //将paper构造成一个发布者
    59         makePublisher(paper);
    60         //已经有了一个发布者。看看订阅对象joe,该对象有两个方法:
    61         var joe = {
    62             drinkCoffee: function(paper) {
    63                 console.log('Just read' + paper);
    64             },
    65             sundayPreNap : function(monthly){
    66                 console.log('About to fall asleep reading this' + monthly);
    67             }
    68         };
    69         //paper注册joe(即joe向paper订阅)
    70         paper.subscribe(joe.drinkCoffee);
    71         paper.subscribe(joe.sundayPreNap,'monthly');
    72         //即joe为默认“any”事件提供了一个可被调用的方法,而另一个可被调用的方法则用于当“monthly”类型的事件发生时的情况。现在让我们来触发一些事件:
    73         paper.daily();      //Just readbig news today
    74         paper.daily();      //Just readbig news today
    75         paper.monthly();    //About to fall asleep reading thisinteresting analysis
    76         paper.monthly();    //About to fall asleep reading thisinteresting analysis
    77         paper.monthly();

    自己又试着实现了一下

     1     var publisher = {
     2         subscribers: {
     3             'any': []
     4         },
     5         subscribe: function(fn, type){
     6             var type = type || 'any';
     7             if(typeof this.subscribers[type] === 'undefined'){
     8                 this.subscribers[type] = [];
     9             }
    10             this.subscribers[type].push(fn);
    11         },
    12         unsubscribe: function(fn, type){
    13             this.visitSubscribers('unsubscribe', fn, type);
    14         },
    15         publish: function(publication, type){
    16             this.visitSubscribers('publish', publication, type);
    17         },
    18         visitSubscribers: function(action, arg, type){
    19             var type = type || 'any';
    20             if(typeof this.subscribers[type] === 'undefined'){
    21                 this.subscribers[type] = [];
    22             }
    23             for(var i=0, len = this.subscribers[type].length; i<len; i++){
    24                 if(action === 'unsubscribe'){
    25                     if(this.subscribers[type][i] === arg){
    26                         this.subscribers[type].splice(i,1);
    27                     }
    28                 } else {
    29                     this.subscribers[type][i](arg);
    30                 }
    31             }
    32         }
    33     };
    34 
    35     function makePublisher(obj){
    36         var i;
    37         for(i in publisher){
    38             if(publisher.hasOwnProperty(i)  && typeof publisher[i] === 'function'){
    39                 obj[i] = publisher[i];
    40             }
    41         }
    42         obj['subscribers'] = {'any':[]};
    43     }
    44 
    45     var paper = {
    46         daily: function(news){
    47             this.publish(news);
    48         },
    49         monthly : function(news){
    50             this.publish(news, 'monthly');
    51         }
    52     }
    53     makePublisher(paper);
    54 
    55     var Jack = {
    56         drinkCoffee: function(publication){
    57             console.log('Jack read '+ publication +' while drinking coffe');
    58         },
    59         watchTV : function(publication){
    60             console.log('Jack read ' + publication + ' while watching TV');
    61         }
    62     }
    63     var Amy = {
    64         AmyDrinkCoffee: function(publication){
    65             console.log('Amy read '+ publication +' while drinking coffe');
    66         },
    67         AmyWatchTV : function(publication){
    68             console.log('Amy read ' + publication + ' while watching TV');
    69         }
    70     }
    71 
    72     paper.daily();
    73     paper.monthly();
    74     paper.subscribe(Jack.drinkCoffee);
    75     paper.subscribe(Jack.watchTV, 'monthly');                                                           
    76     paper.subscribe(Amy.AmyDrinkCoffee, 'monthly');
    77     paper.subscribe(Amy.AmyWatchTV);
    78 
    79     console.log('paper发布daily');
    80     paper.daily(' today is Sunday ');       //Jack read  today is Sunday  while drink coffe  
    81                                             //Amy read  today is Sunday  while watch TV 
    82     console.log('paper发布monthly');
    83     paper.monthly(' this month is Aug. ');  //Jack read  this month is Aug.  while drink coffe
    84                                             //Amy read  this month is Aug.  while watch TV
    85     console.log('Amy取消了monthly的订阅');
    86 
    87     paper.unsubscribe(Amy.AmyWatchTV);
    88     paper.daily(' today is Friday ');           //Jack read  today is Friday  while drinking coffe
    89     paper.monthly(' next weekend is Sept. ');   //Jack read  next weekend is Sept.  while watching TV
    90                                                 //Amy read  next weekend is Sept.  while drinking coffe
    自己尝试实现

    试着用函数实现:

     1         function Publisher(subscribers){
     2             this.subscribers = subscribers || {'any': []};
     3             Publisher.prototype.subscribe = function(fn, type){
     4                 var type = type || 'any';
     5                 if(typeof this.subscribers[type] === 'undefined'){
     6                     this.subscribers[type] = [];
     7                 }
     8                 this.subscribers[type].push(fn);
     9             };
    10             Publisher.prototype.unsubscribe = function(fn, type){
    11                 var type = type || 'any';
    12                 for(var i=0, len = this.subscribers[type].length;  i<len; i++){
    13                     if(this.subscribers[type][i] === fn){
    14                         this.subscribers[type].splice(i,1);
    15                     }
    16                 }
    17             };
    18             Publisher.prototype.publish = function(publication, type){
    19                 var type = type || 'any';
    20                 for(var i=0, len = this.subscribers[type].length; i<len; i++){
    21                     this.subscribers[type][i](publication);
    22                 }
    23             };
    24         }
    25 
    26 
    27         var paper = new Publisher();
    28         paper.daily = function(){
    29             this.publish(' this is Olympic ! ');
    30         };
    31         paper.monthly = function(){
    32             this.publish(' last month is the 28th Olympic! ', 'monthly');
    33         };
    34 
    35         var Jack = {
    36             readInMorning: function(news){
    37                 console.log('Jack reads ' + news + ' in the morning');
    38             },
    39             readInSunday: function(news){
    40                 console.log('Jack reads ' + news + ' on Sunday');
    41             }
    42         };
    43 
    44         var Amy = {
    45             readInMorning: function(news){
    46                 console.log('Amy reads ' + news + ' in the morning');
    47             },
    48             readInSunday: function(news){
    49                 console.log('Amy reads ' + news + ' on Sunday');
    50             }
    51         };
    52 
    53         paper.subscribe(Jack.readInMorning);
    54         paper.subscribe(Jack.readInSunday, 'monthly');
    55         paper.subscribe(Amy.readInMorning);
    56         paper.subscribe(Amy.readInSunday, 'monthly');
    57 
    58         paper.daily();          //Jack reads  this is Olympic !  in the morning
    59                                 //Amy reads  this is Olympic !  in the morning
    60         paper.monthly();        //Jack reads  last month is the 28th Olympic!  on Sunday
    61                                 //Amy reads  last month is the 28th Olympic!  on Sunday
    62 
    63         paper.unsubscribe(Jack.readInSunday,'monthly');
    64         paper.daily();              //Jack reads  this is Olympic !  in the morning
    65                                     //Amy reads  this is Olympic !  in the morning
    66         paper.monthly();            //Amy reads  last month is the 28th Olympic!  on Sunday
    67         
  • 相关阅读:
    大话设计模式(二)代理模式 工厂方法模式 原型模式 模板方法模式 迪米特法模式 外观模式
    大话设计模式(一)简单工厂模式 策略模式 单一职责原则 开放-封闭原则 依赖倒置原则 装饰模式
    eclipse为hibernate.cfg.xml添加自动提示【转】
    Caused by: java.lang.NoSuchMethodError: javax.persistence.spi.PersistenceUnitInfo.getValidationMode
    Chrome 浏览器提示adobe flash player不是最新版本
    spring mvc <mvc:default-servlet-handler /> 。
    S2SH CRUD 整合
    Ms sql行转列。汇总
    Hibernate中的数据库方言(Dialect)
    SSH整合(1)异常
  • 原文地址:https://www.cnblogs.com/haoyijing/p/5761593.html
Copyright © 2011-2022 走看看