js设计模式总结-迭代器模式

迭代器模式

要解决的问题

迭代器要解决的问题很简单很单纯,就是进行遍历操作。

实现原理

基本所有语言都实现了迭代器,javascript也不例外,如Array.prototype.forEachfor..of..for..in..for
迭代器的种类分两种,内部迭代器,外部迭代器。

内部迭代器

内部迭代器的迭代过程对外部是不可控的,内部自己实现迭代过程.比如forEach, jQuery中的$.each

外部迭代器

外部迭代器就相对灵活,可以控制迭代过程,需要显式调用迭代操作.外部迭代器较内部迭代器来说更方便扩展。

外部迭代器的一个实现

    // itObj 是被迭代对象,需要包含length属性
    var Iterator = function(itObj) {
        this.obj = itObj
        this.currentItem = 0
        this.length = itObj.length
    }

    Iterator.prototype.next = function() {
        if (this.currentItem < this.length) {
            this.currentItem++
        }
    }

    Iterator.prototype.getCurrentItem = function() {
        return this.obj[this.currentItem]
    }

    Iterator.prototype.isDone = function() {
        return this.currentItem >= this.length
    }

    var it = new Iterator([1, 2, 3])
    console.log(it.getCurrentItem()) // 1
    it.next()
    console.log(it.getCurrentItem()) // 2
    it.next()
    console.log(it.getCurrentItem()) // 3
    it.next()
    console.log(it.getCurrentItem()) // 3

扩展我们的迭代器,实现两个数组的merge函数

    //两个迭代器
    var it1 = new Iterator([1,3,4,6])
    var it2 = new Iterator([2,3,5,7])

    var merge = function(it1, it2) {
        var tmp = []
        // 两个迭代器同时遍历
        while(!it1.isDone() && !it2.isDone()) {
            if (it1.getCurrentItem() > it2.getCurrentItem()) {
                tmp.push(it2.getCurrentItem())
                it2.next()
            } else if (it1.getCurrentItem() < it2.getCurrentItem()) {
                tmp.push(it1.getCurrentItem())
                it1.next()
            } else {
                tmp.push(it1.getCurrentItem())
                it1.next()
                it2.next()
            }
        }
        // 如果it1没被遍历完,直接push
        while(!it1.isDone()) {
            tmp.push(it1.getCurrentItem())
            it1.next()
        }
        // 如果it2没被遍历完,直接push
        while(!it2.isDone()) {
            tmp.push(it2.getCurrentItem())
            it2.next()
        }
        return tmp
    }

    console.log(merge(it1, it2)) // [1, 2, 3, 4, 5, 6, 7]

可以看到用外部迭代器很容易地控制迭代过程,扩展功能

实践中的应用

一个copy自书上的例子

获取上传对象

未使用迭代器的版本

    var getUploadObj = function() {
		try {
			return new ActiveXObject("TXFTNActiveX.FTNUpload");
		} catch (e) {
			// IE 上传控件
			if (supportFlash()) { // 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'));
			}
		}
	}

我们看到其中夹杂着try...catch语句和大量的if语句,严重违反了开闭原则。
使用迭代器重构

   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" class="ui-file" />'
        return $(str).appendTo($('body'))
    }

    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)

重构代码之后,我们可以看到,获取不同上传对象的方法被隔离在各自的函数里互不干扰, try、catch 和 if 分支不再纠缠在一起,使得我们可以很方便地的维护和扩展代码。

posted @ 2016-11-09 17:46  Xinyu520  阅读(595)  评论(0)    收藏  举报