Javascript设计模式之我见:迭代器模式

大家好!本文介绍迭代器模式及其在Javascript中的应用。

模式介绍

定义

提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象内部表示。

类图及说明

Javascript设计模式之我见:迭代器模式

 

Iterator抽象迭代器

抽象迭代器负责定义访问和遍历元素的接口,而且基本上是有固定的3个方法:first()获得第一个元素,next()访问下一个元素,isDone()(或者为hasNext())是否已经访问到底部

ConcreIterator具体迭代器

具体迭代器角色要实现迭代器接口,完成容器元素的遍历。

Aggregate抽象容器

容器角色负重提供创建具体迭代器角色的接口,必然提供一个类似createIterator()(或者为iterator())这样的方法。

Concrete Aggregate具体容器

具体容器实现容器接口定义的方法,创建出容纳迭代器的对象。

应用场景

  • 访问一个聚合对象的内容而无需暴露它的内部表示。

  • 支持对聚合对象的多种遍历。 

  • 为遍历不同的聚合结构提供一个统一的接口。

优点

  1. 支持以不同的方式遍历一个聚合,复杂的聚合可用多种方式进行遍历。
  2. 迭代器简化了聚合的接口。有了迭代器的遍历接口,聚合本身就不需要类似的遍历接口了,这样就简化了聚合的接口。
  3. 在同一个聚合上可以有多个遍历 每个迭代器保持它自己的遍历状态。因此你可以同时进行多个遍历。

缺点 

  1. 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
  2. 抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展,例如 JDK 内置迭代器 Iterator 就无法实现逆向遍历,如果需要实现逆向遍历,只能通过其子类ListIterator 等来实现,而 ListIterator 迭代器无法用于操作 Set 类型的聚合对象。在自定义迭代器时,创建一个考虑全面的抽象迭代器并不是件很容易的事情。

迭代器模式在Javascript中的应用

我的理解

抽象迭代器角色

定义对数据结构的通用基本操作。如hasNext、next等。

具体迭代器角色

实现对某一类数据结构的基本操作。如ArrIterator实现对数组结构的基本操作,hashIterator实现对hash结构的基本操作

容器角色

实现数据结构的特定操作。

类图及说明

介绍两种形式的应用:

继承

优点

  • 容器类可直接复用迭代器的操作,不用再提供方法iterator来获得迭代器实例了。

缺点

  • 容器类继承了迭代器的所有操作,有些操作它可能不会用到。
  • 限定了迭代器的扩展,在修改迭代器时可能会影响到容器类。

适用场合

  • 迭代器比较简单
  • 容器类需要使用所有的迭代器方法

委托

 Javascript设计模式之我见:迭代器模式

优点

  • 容器类可以只使用迭代器的部分操作。
  • 灵活,便于容器类与迭代器类扩展。

缺点

  • 容器类中需要增加委托方法iterator。

适用场合

  • 迭代器类和容器类需要扩展

示例

大神可以拿各种offer,屌丝表示很是好奇。一天屌丝偷偷搞到了大神读的书籍清单,于是迫不及待地打开,想看个究竟。

类图

Javascript设计模式之我见:迭代器模式

代码

代码中使用的库:YOOP

IBook

var IBook = YYC.Interface("showInfo");

Book

    var Book = YYC.Class({Interface: IBook}, {

        Init: function (name) {

            this._name = name;

        },

        Private: {

            _name: ""

        },

        Public: {

            showInfo: function () {

                console.log(this._name);

            }

        }

    });

场景类

    function main(){

         //定义一个数组容器,存放所有的书对象

        var container, i, len;



        container = [];

        i = 0;

        len = 0;



        container.push(new Book("设计模式之禅"));

        container.push(new Book("Http权威指南"));

        container.push(new Book("深入理解计算机操作系统"));



        for(i = 0, len = container.length; i < len; i++){

                container[i].showInfo();

        }

    }

 运行结果

示例分析

场景类中实现了一个数组容器及其遍历。应该把容器的实现封装起来形成容器类,令场景类调用容器的接口方法。

另外,容器类中访问数组容器元素的逻辑具有通用性,可以提出来形成迭代器类。凡是需要访问数组容器元素的容器类,只要使用迭代器类就可以实现。

使用迭代器模式

现在分别用继承和委托的方式来实现。

继承

可以将内部容器container放到Iterator类中。

类图

Javascript设计模式之我见:迭代器模式

代码

IIterator

var IIterator = YYC.Interface("hasNext", "next");

Iterator

var Iterator = YYC.Class({Interface: IIterator}, {

    Init: function () {

    },

    Private: {

        _container: [],

        _cursor: 0

    },

    Public: {

        hasNext: function () {

            if (this._cursor === this._container.length) {

                return false;

            }

            else {

                return true;

            }

        },

        next: function () {

            var result = null;



            if (this.hasNext()) {

                result = this._container[this._cursor];

                this._cursor += 1;

            }

            else {

                result = null;

            }



            return result;

        }

    }

});

BookContainer

     var BookContainer = YYC.Class(Iterator, {

         Init: function(){},

         Public: {

             add: function(name){

                 this._container.push(new Book(name));

             },

             showInfo: function(){

                 while(this.hasNext()){

                     this.next().showInfo();

                 }

             }

         }

     });

IBook

var IBook = YYC.Interface("showInfo");

Book

var Book = YYC.Class({Interface: IBook}, {

    Init: function (name) {

        this._name = name;

    },

    Private: {

        _name: ""

    },

    Public: {

        showInfo: function () {

            console.log(this._name);

        }

    }

});

场景类Client

function main() {

    var container = new BookContainer();



    container.add("设计模式之禅");

    container.add("Http权威指南");

    container.add("深入理解计算机操作系统");



    container.showInfo();

}

委托

Iterator中通过注入获得内部容器container。

类图

 Javascript设计模式之我见:迭代器模式

代码

IIterator

var IIterator = YYC.Interface("hasNext", "next");

Iterator

var Iterator = YYC.Class({Interface: IIterator}, {

    Init: function (container) {

        this._container = container;

    },

    Private: {

        _container: [],

        _cursor: 0

    },

    Public: {

        hasNext: function () {

            if (this._cursor === this._container.length) {

                return false;

            }

            else {

                return true;

            }

        },

        next: function () {

            var result = null;



            if (this.hasNext()) {

                result = this._container[this._cursor];

                this._cursor += 1;

            }

            else {

                result = null;

            }



            return result;

        }

    }

});

IBookContainer

var IBookContainer = YYC.Interface("add", "iterator");

BookContainer

var BookContainer = YYC.Class({ Interface: IBookContainer }, {

    Init: function () {

    },

    Private: {

        _container: []

    },

    Public: {

        add: function (name) {

            this._container.push(new Book(name));

        },

        iterator: function () {

            return new Iterator(this._container);

        }

    }

});

IBook

var IBook = YYC.Interface("showInfo");

Book

var Book = YYC.Class({Interface: IBook}, {

    Init: function (name) {

        this._name = name;

    },

    Private: {

        _name: ""

    },

    Public: {

        showInfo: function () {

            console.log(this._name);

        }

    }

});

场景类Client

function main() {

    var container, iter;



    container = new BookContainer();



    container.add("设计模式之禅");

    container.add("Http权威指南");

    container.add("深入理解计算机操作系统");





    iter = container.iterator();



    while (iter.hasNext()) {

        iter.next().showInfo();

    }

}

变形

  上面将容器类BookContainer的showInfo方法放到场景类中实现。也可以将其放到BookContainer中,这样BookContainer就不需要iterator方法了。

IBookContainer

var IBookContainer = YYC.Interface("add", "showInfo");

BookContainer

var BookContainer = YYC.Class({ Interface: IBookContainer }, {

    Init: function () {

        this._iter = new Iterator(this._container);

    },

    Private: {

        _container: [],

        _iter: null

    },

    Public: {

        add: function (name) {

            this._container.push(new Book(name));

        },

        showInfo: function () {

            while (this._iter.hasNext()) {

                this._iter.next().showInfo();

            }

        }

    }

});

场景类

function main() {

    var container = new BookContainer();



    container.add("设计模式之禅");

    container.add("Http权威指南");

    container.add("深入理解计算机操作系统");



    container.showInfo();

}

运行结果

 

示例分析

  为什么add放到容器类BookContainer,而不是放到迭代器Iterator中呢?

add: function (name) {

    this._container.push(new Book(name));

},

因为在add方法中需要创建Book实例,因此与容器元素Book强耦合。而Iterator中都是容器的基本操作,是不需要知道具体的容器元素的。所以add不能放到Iterator中。

又因为add属于容器操作,因此应该放到作为容器类的BookContainer中。

参考资料

《设计模式之禅》

迭代器模式

你可能感兴趣的:(JavaScript)