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设计模式》之代理模式
一.定义 代理是一个对象,它可以用来控制对另一个对象的访问.它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象.另外那个对象通常称为本体.代理可以代替其实体被实例化,并使其可被远程访 ...
随机推荐
- 【原创】Java实现手机号码归属地查询
网络上已经有很多的手机号码归属地查询的API接口,但是这些接口总是有一些大大小小的缺陷. 总结一下这些缺陷: 1.要直接将它的搜索框链接形式粘到自己的页面,点击查询的时候还要跳转到他们的网站来展示归属 ...
- maven 仓库搜索添加需要的jar包
可用仓库网址: http://search.maven.org/#browse http://mvnrepository.com/ http://repository.sonatype.org/ind ...
- hdu 3064 twoNumber
twoNumber Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 2048/1024 K (Java/Others) Total Su ...
- .net framework 4.6.2 下载
.net framework .net framework版本: 4.6.2 File Name: NDP462-KB3151800-x86-x64-AllOS-ENU.exe 发布日期: 201 ...
- java PKCS7Padding 加密Cannot find any provider supporting AES/CBC/PKCS7Padding 解决办法
在java中用aes256进行加密,但是发现java里面不能使用PKCS7Padding,而java中自带的是PKCS5Padding填充,那解决办法是,通过BouncyCastle组件来让java里 ...
- 边工作边刷题:70天一遍leetcode: day 101
dp/recursion的方式和是不是game无关,和game本身的规则有关:flip game不累加值,只需要一个boolean就可以.coin in a line II是从一个方向上选取,所以1d ...
- [转载]ExtJs4 笔记(4) Ext.XTemplate 模板
作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/)版权声明:本文的版权归作者与博客园共有.转载时须注明本文的详细链接,否则作者将保留追究其法律 ...
- UVA 103 Stacking Boxes --LIS
实际上是一个扩展维度的矩形嵌套问题. 一个物体能嵌入另一个物体中,当且仅当这个物体的所有维度的长度都小于另外一个(本题是小于等于),又因为可以旋转等变换,所以干脆将每个箱子的边从小到大排序,以便于判断 ...
- 使用Unity3D引擎开发赛车游戏
Car Tutorial 在Unity3D的Asset Store有一个赛车的Demo —— Car Tutorial,看起来特别酷的赛车游戏Demo,不过我还没有下载下来,因为在公司下载Assets ...
- AppScan Source V8.8 中弃用的功能
从 AppScan Source V8.8 开始,不再支持以下操作系统: Microsoft Windows XP Microsoft Windows Server 2003,所有版本和修订版 此 ...