美文网首页
迭代器模式

迭代器模式

作者: 般犀 | 来源:发表于2019-01-08 14:00 被阅读0次

    内部迭代器和外部迭代器

    简单地讲,内部迭代器就是类似 forEach 的迭代器,其内部迭代逻辑已经制定好,只要传入一个可迭代的对象,就会一直迭代。外部迭代器是类似 ES 6 中的 iterator,每一步的迭代都要手动进行。

    迭代器应用举例

    作者介绍了一种场景:有一个项目的上传模块,需要先判断浏览器有什么上传条件,根据优先级选出适合的上传模式,原来的代码是这样的:

    var getUploadObj = function() {
      try {
        return new ActiveXObject("TXFTNActiveX.FTNUpload");  // IE 上传控件
      } catch (e) {
        if (supportFlash()) {
          var str = '<object type="application/x-shockwave-flash"></object>';
          return $('str').appendTo($('body'));
        } else {
          var str = '<input name="file" type="file" />';
          return $('str').appendTo($('body'));
        }
      }
    }
    

    作者是一个 if...else 强迫症,看到一个函数里有这么多 if...else ,还有 try...catch 语句,他觉得不行,我也觉得这样不好。不仅有很多条件判断语句,也违反 开放-封闭 原则,以后如果增加了其他的上传方式,如 HTML 5 上传,那就要再次改写这个函数。

    这个时候就可以使用迭代器模式,将每种判断的方法抽出来变成一个个方法,然后将各个方法作为函数的参数参入另一个函数中,在函数中按优先级迭代出合适的方法出来即可:

    var getActiveUploadObj = function() {
       try {
        return new ActiveXObject("TXFTNActiveX.FTNUpload"); // IE 上传控件
      } catch (e) {
        return false;
      }
    };
    var getFlashUploadObj = function() {
      if(supportFlash()) {
        var str = '<object type="application/x-shockwave-flash"></object>';
        return $('str').appendTo($('body'));
      }
      return false;
    }
    var getFormUploadObj = function() {
      var str = '<input name="file" type="file" />';
      return $('str').appendTo($('body'));
    }
    

    这三个函数都遵循了一个规则:如果该函数下的 Upload 对象是可用的,就返回该对象,反之则返回 false,让迭代继续往后面迭代。

    接着,我们再实现迭代这三个函数的函数:

    var iteratorUploadObj = function() {
      for (var i = 0, fn; fn = arguments[i++];) {
        var uploadObj = fn();
        if (uploadObj !== false) {
            return uploadObj;
        }
      }
    }
    
    var uploadObj = iteratorUploadObj(getActiveUploadObj, getFlashUploadObj, getFormUploadObj);
    

    这样写后,方法可以按优先级进行迭代,如果要添加新的上传方法,只需要往 iteratorUploadObj 传入新的参数即可,不需要修改已经写好的代码。简直棒棒。

    与策略模式的对比

    在前面的策略模式中,使用策略模式的痛点也在于一个函数里的 if...else 条件语句过多,那么什么时候用策略模式,什么时候用迭代器模式呢?

    通过观察策略模式的使用,可以发现,策略模式的策略是被“显式调用”的,如前面的计算奖金场景下,先写好一个策略对象,里面是不同绩效下的不同策略,然后再写一个函数,用于将绩效等级传入,而绩效等级的名称刚好对应上了策略对象里不同策略的属性名。是一个“显式调用的过程”。
    再比如缓动动画的案例里,将各种缓动函数写在了一个对象里,需要用到什么缓动,就调用哪个方法。

    而迭代器模式是将方法一个个传入,我们并不知道哪个方法会生效。属于一股脑传进去,我们对选择哪个方法做不了主,所以才用到了迭代器。

    所以以后如果有想要规避条件语句的情景,可以看看调用的方法我们是不是已经明确,明确了可以使用策略模式,不明确可以使用迭代器模式。

    关于 arguments 对象的使用

    在代理模式和策略模式中,发现很多代码用到了 arguments对象和 apply 方法,但是我在实际开发中很少用到这两个。而不使用 arguments的原因,大概是对这个对象有点“抵触”的情绪,因为在当时阅读《Javascript 高级程序设计》的过程中,看到书中说在严格模式下,argumentscalleecaller方法是不允许使用的,且arguments对象不允许修改(删除,添加元素),这让我感觉到使用arguments是一件不好的事情,但是实际上,虽然不能修改arguments对象,但是读取和遍历arguments对象是允许的,而且可以让一些操作变得简便,比如策略模式中的遍历就用到了。所以以后在一些场景下可以考虑用用 arguments

    相关文章

      网友评论

          本文标题:迭代器模式

          本文链接:https://www.haomeiwen.com/subject/exbvrqtx.html