大家好!本文介绍迭代器模式及其在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来获得迭代器实例了。

缺点

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

适用场合

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

委托

优点

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

缺点

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

适用场合

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

示例

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

类图

代码

代码中使用的库: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 = ;
len = ; container.push(new Book("设计模式之禅"));
container.push(new Book("Http权威指南"));
container.push(new Book("深入理解计算机操作系统")); for(i = , len = container.length; i < len; i++){
container[i].showInfo();
}
}

运行结果

示例分析

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

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

使用迭代器模式

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

继承

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

类图

代码

IIterator

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

Iterator

var Iterator = YYC.Class({Interface: IIterator}, {
Init: function () {
},
Private: {
_container: [],
_cursor:
},
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 += ;
}
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。

类图

代码

IIterator

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

Iterator

var Iterator = YYC.Class({Interface: IIterator}, {
Init: function (container) {
this._container = container;
},
Private: {
_container: [],
_cursor:
},
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 += ;
}
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设计模式之我见:迭代器模式的更多相关文章

  1. javascript设计模式学习之七——迭代器模式

    一.迭代器模式定义 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,并且不需要暴露该对象的内部表示. 在当前大部分语言中,都已经内置了迭代器模式.迭代器有内部迭代器和外部迭代器之分,一般现有语 ...

  2. 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)

      设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的 ...

  3. [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

    <JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...

  4. 《Head first设计模式》之迭代器模式

    迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示. 爆炸性新闻:对象村餐厅和对象村煎饼屋合并了! 真是个好消息!现在我们可以在同一个地方,享用煎饼屋美味的煎饼早餐,和好吃 ...

  5. javascript设计模式--策略模式

    javascript策略模式总结 1.什么是策略模式? 策略模式的定义是:定义一系列的算法,把他们独立封装起来,并且可以相互替换. 例如我们需要写一段代码来计算员工的奖金.当绩效为a时,奖金为工资的5 ...

  6. JavaScript 设计模式: 发布者-订阅者模式

    JavaScript 设计模式: 发布者-订阅者模式 发布者-订阅者模式 https://github.com/Kelichao/javascript.basics/issues/22 https:/ ...

  7. Javascript设计模式之我见:状态模式

    大家好!本文介绍状态模式及其在Javascript中的应用. 模式介绍 定义 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是控制一个对象状态的条件表达式 ...

  8. javascript设计模式实践之迭代器--具有百叶窗切换图片效果的JQuery插件(一)

    类似于幻灯片的切换效果,有时需要在网页中完成一些图片的自动切换效果,比如广告,宣传,产品介绍之类的,那么单纯的切就没意思了,需要在切换的时候通过一些效果使得切换生动些. 比较常用之一的就是窗帘切换了. ...

  9. 【读书笔记】读《JavaScript设计模式》之代理模式

    一.定义 代理是一个对象,它可以用来控制对另一个对象的访问.它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象.另外那个对象通常称为本体.代理可以代替其实体被实例化,并使其可被远程访 ...

随机推荐

  1. leangoo更换背景、设置颜色标签功能上线啦!

    leangoo看板背景太单调?卡片标签想要添加多个?没有问题,Leangoo的本次更新就给大家带来了漂亮背景和实用的颜色标签设置,接下来就让我们一起来看看吧! 设置背景: 点击看板右上角个人头像图标按 ...

  2. Js中获取对象的所有key值

    假如现在有一个对象 var obj = { A:2 ,B:"Ray" ,C:true ,D:function(){} } 如果想遍历对象obj中的所有键值,一般是用以下方式 for ...

  3. 50个jquery代码片段(转)

    本文会给你们展示50个jquery代码片段,这些代码能够给你的javascript项目提供帮助.其中的一些代码段是从jQuery1.4.2才开始支持的做法,另一些则是真正有用的函数或方法,他们能够帮助 ...

  4. 烂泥:KVM中安装Windows Server 2008 R2系统

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 在前一篇文章中,我介绍了有关在KVM中的安装Centos系统.接下来,就来介绍如何在KVM中安装Windows系统. 注意:在此我安装的是windows ...

  5. hdu 2255 奔小康赚大钱--KM算法模板

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:有N个人跟N个房子,每个人跟房子都有一定的距离,现在要让这N个人全部回到N个房子里面去,要 ...

  6. C++ transform

    transform函数的作用是:将某操作应用于指定范围的每个元素.transform函数有两个重载版本: transform(first,last,result,op);//first是容器的首迭代器 ...

  7. selenium循环点击文本框

    1.可以用xpath循环点击checkbox List<WebElement> list = dr.findElements(By.className("datagrid-row ...

  8. 单元测试---googletest

    单元测试概述 测试并不只是测试工程师的责任,对于开发工程师,为了保证发布给测试环节的代码具有足够好的质量( Quality ),为所编写的功能代码编写适量的单元测试是十分必要的. 单元测试( Unit ...

  9. MySQL遇到check the manual that corresponds to your MySQL server version for the right syntax错误

    用MySQL新建了一个Order表,插入了一条数据.总是显示 You have an error in your SQL syntax; check the manual thatcorrespond ...

  10. AC日记——信息传递 洛谷 P2661 (tarjan求环)

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...