大家好!本文介绍迭代器模式及其在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. python 读写、创建 文件

    python中对文件.文件夹(文件操作函数)的操作需要涉及到os模块和shutil模块. 得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目 ...

  2. Swing应用开发实战系列之一:自定义JdbcTemplate

    笔者本人真正意义上接触编程开发是在2004年,最早用的就是VB,然后是Delphi等,后来转到.Net,中间断断续续还用过PowerBuilder等,无一例外,所研发设计的项目或系统都是WinForm ...

  3. spring mvc 配置文件拦截器过滤url

    最近在用spring mvc拦截器,sprin 版本号4.0.6.RELEASE, <mvc:interceptor> <mvc:mapping path="/admin/ ...

  4. 数据结构--栈的应用(表达式求值 nyoj 35)

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=35 题目: 表达式求值 时间限制:3000 ms | 内存限制:65535 KB描述 AC ...

  5. php类型转换以及类型转换的判别

    部分摘自PHP: 类型 - Manual 相关链接 PHP 在变量定义中不需要(或不支持)明确的类型定义:变量类型是根据使用该变量的上下文所决定的.也就是说,如果把一个 string 值赋给变量 $v ...

  6. ipc之消息队列

    消息队列以链表的方式将消息存储于内核中,调用msgsnd,msgrcv函数往消息队列里面投送,取出指定的消息. 创建一个消息队列 生成一个消息队列或者获取已有消息队列id #include <s ...

  7. elastic search查询命令集合

    Technorati 标签: elastic search,query,commands 基本查询:最简单的查询方式 query:{"term":{"title" ...

  8. 【CSS】颜色码对照表

    英文代码 形像颜色 HEX格式 RGB格式 LightPink 浅粉色 #FFB6C1 255,182,193 Pink 粉红 #FFC0CB 255,192,203 Crimson 猩红 #DC14 ...

  9. linux -- read(), write()

    read()函数 2011-03-23 16:28:37|  分类: linux |  标签: |字号大中小 订阅     read函数从打开的设备或文件中读取数据. #include <uni ...

  10. HTML5秘籍读书笔记

    1:基本雏形 <html><head> <meta charset="UTF-8"> <title></title>&l ...