zoukankan      html  css  js  c++  java
  • JS常用的设计模式(3)-——观察者模式

    观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一. 在很多语言里都得到大量应用. 包括我们平时接触的dom事件. 也是js和dom之间实现的一种观察者模式.

    1 div.onclick  =  function click (){ 
    2    alert ( ''click' ) 
    3 } 

    只要订阅了div的click事件. 当点击div的时候, function click就会被触发.

    那么到底什么是观察者模式呢. 先看看生活中的观察者模式。

    好莱坞有句名言. “不要给我打电话, 我会给你打电话”. 这句话就解释了一个观察者模式的来龙去脉。 其中“我”是发布者, “你”是订阅者。

    再举个例子,我来公司面试的时候,完事之后每个面试官都会对我说:“请留下你的联系方式, 有消息我们会通知你”。 在这里“我”是订阅者, 面试官是发布者。所以我不用每天或者每小时都去询问面试结果, 通讯的主动权掌握在了面试官手上。而我只需要提供一个联系方式。

    观察者模式可以很好的实现2个模块之间的解耦。 假如我正在一个团队里开发一个html5游戏. 当游戏开始的时候,需要加载一些图片素材。加载好这些图片之后开始才执行游戏逻辑. 假设这是一个需要多人合作的项目. 我完成了Gamer和Map模块, 而我的同事A写了一个图片加载器loadImage.

    loadImage的代码如下

    loadImage(  imgAry,  function(){ 
    Map.init(); 
    Gamer.init(); 
    } ) 

    当图片加载好之后, 再渲染地图, 执行游戏逻辑. 嗯, 这个程序运行良好. 突然有一天, 我想起应该给游戏加上声音功能. 我应该让图片加载器添上一行代码.

    1 loadImage(  imgAry,  function(){ 
    2 Map.init(); 
    3 Gamer.init(); 
    4 Sount.init(); 
    5 } ) 

    可是写这个模块的同事A去了外地旅游. 于是我打电话给他, 喂. 你的loadImage函数在哪, 我能不能改一下, 改了之后有没有副作用. 如你所想, 各种不淡定的事发生了. 如果当初我们能这样写呢:

    1 loadImage.listen( ''ready', function(){ 
    2     Map.init(); 
    3 }) 
    4 loadImage.listen( ''ready', function(){ 
    5    Gamer.init(); 
    6 }) 
    7 loadImage.listen( ''ready', function(){ 
    8    Sount.init(); 
    9 }) 

    loadImage完成之后, 它根本不关心将来会发生什么, 因为它的工作已经完成了. 接下来它只要发布一个信号.

    loadImage.trigger( ”ready’ );

    那么监听了loadImage的’ready’事件的对象都会收到通知. 就像上个面试的例子. 面试官根本不关心面试者们收到面试结果后会去哪吃饭. 他只负责把面试者的简历搜集到一起. 当面试结果出来时照着简历上的电话挨个通知.

    说了这么多概念, 来一个具体的实现. 实现过程其实很简单. 面试者把简历扔到一个盒子里, 然后面试官在合适的时机拿着盒子里的简历挨个打电话通知结果.

     1 Events = function() { 
     2            var listen, log, obj, one, remove, trigger, __this; 
     3            obj = {}; 
     4            __this = this; 
     5            listen = function( key, eventfn ) {  //把简历扔盒子, key就是联系方式. 
     6              var stack, _ref;  //stack是盒子 
     7              stack = ( _ref = obj[key] ) != null ? _ref : obj[ key ] = []; 
     8              return stack.push( eventfn ); 
     9            }; 
    10            one = function( key, eventfn ) { 
    11              remove( key ); 
    12              return listen( key, eventfn ); 
    13            }; 
    14            remove = function( key ) { 
    15              var _ref; 
    16              return ( _ref = obj[key] ) != null ? _ref.length = 0 : void 0; 
    17            }; 
    18            trigger = function() {  //面试官打电话通知面试者 
    19              var fn, stack, _i, _len, _ref, key; 
    20              key = Array.prototype.shift.call( arguments );  
    21              stack = ( _ref = obj[ key ] ) != null ? _ref : obj[ key ] = []; 
    22              for ( _i = 0, _len = stack.length; _i < _len; _i++ ) { 
    23                fn = stack[ _i ]; 
    24                if ( fn.apply( __this,  arguments ) === false) { 
    25                  return false; 
    26                } 
    27              } 
    28              return { 
    29                 listen: listen, 
    30                 one: one, 
    31                 remove: remove, 
    32                 trigger: trigger 
    33              } 
    34            } 

    最后用观察者模式来做一个成人电视台的小应用.

    //订阅者

    1 var adultTv = Event(); 
    2 adultTv .listen(  ''play',  function( data ){ 
    3    alert ( "今天是谁的电影" + data.name ); 
    4 }); 
    5 //发布者 
    6 adultTv .trigger(  ''play',  { 'name': '麻生希' }  ) 
  • 相关阅读:
    微信小程序自定义分享图片
    rtop:一个通过 SSH 监控远程主机的交互式工具【转】
    mysql双主+keepalived【转】
    诡异的Linux磁盘空间被占用问题,根目录满了,df和du占用不一样【转】
    linux磁盘空间查看inode
    python数据库操作
    Jenkins 安装及使用
    编程入门python之定义函数【转】
    grep和sed匹配多个字符关键字的用法
    linux 如何删除文件夹下面的文件和文件夹,只保留两个文件
  • 原文地址:https://www.cnblogs.com/jymz/p/4259572.html
Copyright © 2011-2022 走看看