迭代器模式

89 阅读3分钟

内容主要来自《JavaScript设计模式与开发实践》

迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素

现在流行的大多数语言都内置了迭代器,js中就有 for in | for of | forEach 等迭代器语法

使用迭代器,我们可以更方便的实现拓展。如果我们需要实现一个功能,它适用于一些不同的情况,每一种情况都有自己的逻辑需要处理,它们都有相似的调用接口,且相对独立

具体的,书中给出了一个例子:

  • 我们需要实现的功能是上传

  • 上传功能的实现有以下几种方式

    • 浏览器上传控件
    • Flash
    • 浏览器原生表单
      它们之间是相互替换的关系,我们需要确认哪种方式在当前的浏览器中是可用的。

我们可以把每种获取 upload 对象的方法都封装在各自的函数里,然后使用一个迭代器,迭代获取这些 upload 对象,直到获取到一个可用的为止

var getActiveUploadObj = function(){
	try{
		return new ActiveXObject("TXFTNActiveX.FTNUpload"); // IE上传控件
	} cache(e)
	{
		return false;
	}
};

var getFlashUploadObj = function (){
	if( supportFlash () ){
		var str = "<object type = 'application/x-shockwave-flash'> </object>;"
		return false;
	}
}
}

var getFormUploadObj = function(){
	var str = '<input name = "file" type = "file" class = "ui-file" />' // 表单上传
	return $(str).appendTo($("body"));
};

它们三个函数都有同一个约定:如果该函数里面的 upload 对象是可用的,就让该函数返回对象,反之返回false,提示迭代器继续往后面迭代。

迭代器需要完成一下几步工作:

  1. 提供一个可迭代的方法,使得传入的方法依照优先级被循环迭代。
  2. 如果被迭代的函数返回一个对象,则表示找到了正确的 upload对象,反之如果该函数返回 false , 则让迭代器继续工作。

var iteratorUploadObj = function (){
	var uploadObj = fn();
	if( uploadObj !== false ){
		return uploadObj;
	}
}

var uploadObj = iteratorUploadObj( getActiveUploadObj , getFlashUploadObj , getFormUploadObj);

这样使用迭代器之后,我们可以看到,获取不同上传对象的方法被隔离在各自的函数里互不干扰,我们可以很方便的维护和拓展代码。比如,后来我们又给上传项目增加 Webkit 控件上传和 HTML 5 上传, 我们不需要修改原来的代码,只需要做下面的一些工作。

  • 增加分别获取 Webkit 空间上传对象的函数
var getWebkitUploadObj = function (){
//...
}

var getHtml5UploadObj = function (){
//...
}
  • 按照优先级把它们添加进迭代器
var uploadObj = iteratorUploadObj( getActiveUploadObj , getWebkitUploadObj, getFlashUploadObj, getHtml5UploadObj, getFormUploadObj);

小结:

  • 迭代器模式是一种相对比较简单的设计模式, 很多语言都内置了它的实现
  • 我们可以通过约定函数的接口,通过迭代器模式来提高代码的可拓展性。