Javascript设计模式之我见:迭代器模式
大家好!本文介绍迭代器模式及其在Javascript中的应用。
模式介绍
定义
提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象内部表示。
类图及说明

Iterator抽象迭代器
抽象迭代器负责定义访问和遍历元素的接口,而且基本上是有固定的3个方法:first()获得第一个元素,next()访问下一个元素,isDone()(或者为hasNext())是否已经访问到底部
ConcreIterator具体迭代器
具体迭代器角色要实现迭代器接口,完成容器元素的遍历。
Aggregate抽象容器
容器角色负重提供创建具体迭代器角色的接口,必然提供一个类似createIterator()(或者为iterator())这样的方法。
Concrete Aggregate具体容器
具体容器实现容器接口定义的方法,创建出容纳迭代器的对象。
应用场景
访问一个聚合对象的内容而无需暴露它的内部表示。
支持对聚合对象的多种遍历。
为遍历不同的聚合结构提供一个统一的接口。
优点
- 支持以不同的方式遍历一个聚合,复杂的聚合可用多种方式进行遍历。
- 迭代器简化了聚合的接口。有了迭代器的遍历接口,聚合本身就不需要类似的遍历接口了,这样就简化了聚合的接口。
- 在同一个聚合上可以有多个遍历 每个迭代器保持它自己的遍历状态。因此你可以同时进行多个遍历。
缺点
- 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
- 抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展,例如 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设计模式之我见:迭代器模式的更多相关文章
- javascript设计模式学习之七——迭代器模式
一.迭代器模式定义 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,并且不需要暴露该对象的内部表示. 在当前大部分语言中,都已经内置了迭代器模式.迭代器有内部迭代器和外部迭代器之分,一般现有语 ...
- 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)
设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的 ...
- [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1
<JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...
- 《Head first设计模式》之迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示. 爆炸性新闻:对象村餐厅和对象村煎饼屋合并了! 真是个好消息!现在我们可以在同一个地方,享用煎饼屋美味的煎饼早餐,和好吃 ...
- javascript设计模式--策略模式
javascript策略模式总结 1.什么是策略模式? 策略模式的定义是:定义一系列的算法,把他们独立封装起来,并且可以相互替换. 例如我们需要写一段代码来计算员工的奖金.当绩效为a时,奖金为工资的5 ...
- JavaScript 设计模式: 发布者-订阅者模式
JavaScript 设计模式: 发布者-订阅者模式 发布者-订阅者模式 https://github.com/Kelichao/javascript.basics/issues/22 https:/ ...
- Javascript设计模式之我见:状态模式
大家好!本文介绍状态模式及其在Javascript中的应用. 模式介绍 定义 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是控制一个对象状态的条件表达式 ...
- javascript设计模式实践之迭代器--具有百叶窗切换图片效果的JQuery插件(一)
类似于幻灯片的切换效果,有时需要在网页中完成一些图片的自动切换效果,比如广告,宣传,产品介绍之类的,那么单纯的切就没意思了,需要在切换的时候通过一些效果使得切换生动些. 比较常用之一的就是窗帘切换了. ...
- 【读书笔记】读《JavaScript设计模式》之代理模式
一.定义 代理是一个对象,它可以用来控制对另一个对象的访问.它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象.另外那个对象通常称为本体.代理可以代替其实体被实例化,并使其可被远程访 ...
随机推荐
- leangoo更换背景、设置颜色标签功能上线啦!
leangoo看板背景太单调?卡片标签想要添加多个?没有问题,Leangoo的本次更新就给大家带来了漂亮背景和实用的颜色标签设置,接下来就让我们一起来看看吧! 设置背景: 点击看板右上角个人头像图标按 ...
- Js中获取对象的所有key值
假如现在有一个对象 var obj = { A:2 ,B:"Ray" ,C:true ,D:function(){} } 如果想遍历对象obj中的所有键值,一般是用以下方式 for ...
- 50个jquery代码片段(转)
本文会给你们展示50个jquery代码片段,这些代码能够给你的javascript项目提供帮助.其中的一些代码段是从jQuery1.4.2才开始支持的做法,另一些则是真正有用的函数或方法,他们能够帮助 ...
- 烂泥:KVM中安装Windows Server 2008 R2系统
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 在前一篇文章中,我介绍了有关在KVM中的安装Centos系统.接下来,就来介绍如何在KVM中安装Windows系统. 注意:在此我安装的是windows ...
- hdu 2255 奔小康赚大钱--KM算法模板
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:有N个人跟N个房子,每个人跟房子都有一定的距离,现在要让这N个人全部回到N个房子里面去,要 ...
- C++ transform
transform函数的作用是:将某操作应用于指定范围的每个元素.transform函数有两个重载版本: transform(first,last,result,op);//first是容器的首迭代器 ...
- selenium循环点击文本框
1.可以用xpath循环点击checkbox List<WebElement> list = dr.findElements(By.className("datagrid-row ...
- 单元测试---googletest
单元测试概述 测试并不只是测试工程师的责任,对于开发工程师,为了保证发布给测试环节的代码具有足够好的质量( Quality ),为所编写的功能代码编写适量的单元测试是十分必要的. 单元测试( Unit ...
- 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 ...
- AC日记——信息传递 洛谷 P2661 (tarjan求环)
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...