前言

这次要介绍的是迭代器模式,也是一种行为模式。我现在觉得写博客有点应付了,前阵子一天一篇,感觉这样其实有点没理解透彻就写下来了,而且写完后自己也没有多看几遍,上次在面试的时候被问到java中的I/O的各种实现用到了什么设计模式,我愣是想半天没想出来了,人家还给提示了我也没想出来,最后还是面试官给出的答案,是装饰模式,听到答案后就恍然大悟了,前两天刚看了装饰模式,还写下了I/O操作中的各种类都是用到了装饰模式,后来想想两方面原因造成的当时没回答出来,一是面试时紧张就容易想不起来,二是对设计模式理解的还是不够透彻。所以以后宁可写博客慢一些也要将自己写的东西理解透彻了。

迭代器模式

概念介绍

迭代器模式,又称游标模式。这种模式提供一种方法访问一个容器对象中各个元素,而又不需要暴露该对象的内部细节。这种模式其实我们日常开发中也很常见,例如下面的场景:

        java.util.Iterator<String> it = list.iterator();

        while (it.hasNext()){
//using "it.next();" do some business logic
}

这样来理解简单一些,下面还是通过具体的场景例子来实现迭代器模式。

举例

一个书架上放着好几本书,现在我想知道书架上都有哪些书,并且都把书名打印出来。那么书架就可以具有迭代的功能,能把它存放的所有书籍都迭代出来。用代码实现如下:

定义一个迭代器接口,包含检测是否还有下一个元素的方法和获得下一个元素的方法

/**
* 迭代器接口
*/
public interface Iterator { /**
* 检测是否还有下一个元素
* @return
*/
public abstract boolean hasNext(); /**
* 获得下一个元素
* @return
*/
public abstract Object next(); }

定义含有迭代器对象的接口

/**
* 只有实现此接口的才可以获得迭代器对象
*/
public interface Aggregate {
/**
* 获得迭代器对象
* @return
*/
public abstract Iterator iterator();
}

书籍类

/**
* 书籍类
*/
public class Book { //书籍名称
private String name = ""; public Book(String name){
this.name = name;
} /**
* 获得书籍名称
* @return
*/
public String getName(){
return name;
}
}

书架类

/**
* 书架类
*/
public class BookShelf implements Aggregate{ private Book[] books; private int last = 0; public BookShelf(int maxSize){
this.books = new Book[maxSize];
} /**
* 获得书籍
* @param index
* @return
*/
public Book getBookAt(int index){ return books[index]; } /**
* 添加书籍
* @param book
*/
public void appendBook(Book book){
this.books[last] = book;
last++;
} /**
* 获得书架上的书籍数量
* @return
*/
public int getLength(){
return books.length;
} /**
* 获得书架迭代器对象
* @return
*/
@Override
public Iterator iterator(){
return new BookShelfIterator(this);
}
}

书架迭代器

/**
* 书架迭代器
*/
public class BookShelfIterator implements Iterator { private BookShelf bookShelf;
private int index; public BookShelfIterator(BookShelf bookShelf){
this.bookShelf = bookShelf;
this.index = 0;
} /**
* 检测是否还有下一本书
* @return
*/
@Override
public boolean hasNext() {
if(index<bookShelf.getLength()){
return true;
}else {
return false;
}
} /**
* 返回下一本书
* @return
*/
@Override
public Object next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}

测试类

public class Client {

    public static void main(String[] args) {
//创建一个书架
BookShelf bookShelf = new BookShelf(5);
//向书架中添加书籍
bookShelf.appendBook(new Book("深入理解Java虚拟机"));
bookShelf.appendBook(new Book("Java编程思想"));
bookShelf.appendBook(new Book("高性能MySQL"));
bookShelf.appendBook(new Book("Effective Java 中文版"));
bookShelf.appendBook(new Book("数据结构与算法分析Java语言描述"));
//获得书架迭代器
Iterator iterator = bookShelf.iterator();
//迭代
while (iterator.hasNext()){
Book book = (Book) iterator.next();
System.out.println(book.getName());
} } }

运行结果

深入理解Java虚拟机
Java编程思想
高性能MySQL
Effective Java 中文版
数据结构与算法分析Java语言描述

上面的这个例子就是实现了迭代器模式,可以看出来是在客户端和容器间加入了迭代器,这样就很好的避免容器内部细节的暴露,而且也使得设计符合“单一职责原则”。

迭代器模式的结构

迭代器模式主要由以下角色组成

抽象迭代器角色(Iterator):抽象迭代器角色定义访问和遍历元素的接口。上面例子中的Iterator接口就是代表的这个角色。

具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口, 并要记录遍历中的当前位置。上面例子中BookShelfIterator类就是代表的这个角色。

容器角色(Aggregate):容器角色负责提供创建具体迭代器角色的接口。上面的例子中的Aggregate接口代表的就是这个角色。

具体容器角色(Concrete Aggregate):具体容器角色实现创建具体迭代器角色的接口,这个具体迭代器角色与该容器的结构相关。上面例子中书架类BookShelf

代表的就是这个角色。

总结

迭代器模式是一种使用频率非常高的设计模式,通过引入迭代器可以将数据的遍历功能从聚合对象中分离出来,聚合对象只负责存储数据,而遍历数据由迭代器实现完成。Java语言类库中已经实现了迭代器模式,在实际开发中我们直接使用已经定义好的迭代器就可以了,像List、Set等集合都可以直接使用。

优点

1、它支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。替换迭代器就可以切换遍历方法。

2、迭代器简化了聚合类。聚合对象可以不用自己再提供遍历方法。

3、在迭代器模式中由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足“开闭原则”的要求。

缺点

1、由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器来,类的个数成对增加,这在一定程度上增加了系统的复杂性。

2、抽象迭代器设计难度相对较大,需要充分考虑到系统将来的扩展,,例如JDK内置迭代器Iterator就无法实现逆向遍历,如果需要实现逆向遍历,只能通过其子类ListIterator等来实现,而ListIterator迭代器无法用于操作Set类型的聚合对象。

适用场景

在以下情况可以考虑使用迭代器模式

1、访问一个聚合对象的内容而无须暴露它的内部表示。将聚合对象的访问与内部数据的存储分离,使得访问聚合对象时无须了解其内部实现细节。

2、需要为一个聚合对象提供多种遍历方式。

3、为遍历不同聚合结构提供统一的接口,该接口的实现类中为不同的聚合结构提供不同的遍历方式,而客户端可以一致性的操作该接口。

想了解更多的设计模式请查看Java设计模式学习记录-GoF设计模式概述

Java设计模式学习记录-迭代器模式的更多相关文章

  1. Java设计模式学习记录-模板方法模式

    前言 模板方法模式,定义一个操作中算法的骨架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤. 模板方法模式 概念介绍 模板方法模式,其实是很好理解的,具体 ...

  2. Java设计模式学习记录-状态模式

    前言 状态模式是一种行为模式,用于解决系统中复杂的对象状态转换以及各个状态下的封装等问题.状态模式是将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象的状态可以灵活多变.这样在客户端使 ...

  3. Java设计模式学习记录-备忘录模式

    前言 这次要介绍的是备忘录模式,也是行为模式的一种 .现在人们的智能手机上都会有备忘录这样一个功能,大家也都会用,就是为了记住某件事情,防止以后自己忘记了.那么备忘录模式又是什么样子的呢?是不是和手机 ...

  4. Java设计模式学习记录-解释器模式

    前言 这次介绍另一个行为模式,解释器模式,都说解释器模式用的少,其实只是我们在日常的开发中用的少,但是一些开源框架中还是能见到它的影子,例如:spring的spEL表达式在解析时就用到了解释器模式,以 ...

  5. Java设计模式学习记录-命令模式

    前言 这次要介绍的是命令模式,这也是一种行为型模式.最近反正没有面试机会我就写博客呗,该投的简历都投了.然后就继续看书,其实看书也会给自己带来成就感,原来以前不明白的东西,书上已经给彻底的介绍清楚了, ...

  6. Java设计模式学习记录-外观模式

    前言 这次要介绍的是外观模式(也称为门面模式),外观模式也属于结构型模式,其实外观模式还是非常好理解的,简单的来讲就是将多个复杂的业务封装成一个方法,在调用此方法时可以不必关系具体执行了哪些业务,而只 ...

  7. Java设计模式学习记录-桥接模式

    前言 这次介绍结构型设计模式中的第二种模式,桥接模式. 使用桥接模式的目的就是为了解耦,松散的耦合更利于扩展,但是会增加相应的代码量和设计难度. 桥接模式 桥接模式是为了将抽象化与实现化解耦,让二者可 ...

  8. Java设计模式学习记录-代理模式

    代理模式 代理模式是常见设计模式的一种,代理模式的定义是:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起 ...

  9. Java设计模式学习记录-建造者模式

    前言 今天周末,有小雨,正好也不用出门了,那就在家学习吧,经过了两周的面试,拿到了几个offer,但是都不是自己很想去的那种,要么就是几个人的初创小公司,要么就是开发企业内部系统的这种传统开发,感觉这 ...

随机推荐

  1. 注解@ResponseBody的作用

    @ResponseBody通常是放在方法上,主要是在前端页面异步请求的时候,返回数据使用.直白点说就是加上这个注解之后,return的数据不会解析成返回跳转路径,而是会默认放在  response b ...

  2. springMVC学习 十二 拦截器

    一 拦截器概述 拦截器技术比较像java web技术中的过滤器技术,都是发送 请求时被拦截器拦截,在控制器的前后添加额外功能.但是和Spring中的Aop技术是由区别的.AOP 在特定方法前后扩充(一 ...

  3. Vuejs——(1)入门(单向绑定、双向绑定、列表渲染、响应函数)

    版权声明:出处http://blog.csdn.net/qq20004604   目录(?)[+]   参照链接: http://cn.vuejs.org/guide/index.html [起步]部 ...

  4. Java RMI 使用例子

    1.创建协议接口(UserService) /** * */ package com.junge.demo.rmi.protocol.service; import java.io.Serializa ...

  5. C# 多线程 举例使用

    使用多线程的几种方式 (1)不需要传递参数,也不需要返回参数 ThreadStart是一个委托,这个委托的定义为void ThreadStart(),没有参数与返回值.   /// <summa ...

  6. Android 经验之文件下载

    在Android 开发中,我们肯定会接触到下载需求,那么如何通过技术实现呢? 一.简单实现: 通过了解HTTP原理,我们应该可以知道,HTTP学习的时候,可以通过HTTPGET方式来进行文件下载: n ...

  7. Windows 系统 IP 和端口的相关检测命令

    查看本机IP地址 查看自己电脑的ip,使用 ipconfig 命令 ipconfig 检测指定IP是否联通 检测某个ip是否可以连通,直接使用 ping 命令 ping 219.148.111.212 ...

  8. 关于No mapping found for HTTP request with URI...

    当你看到这篇博客,说明你已经像我一样快疯了!但是还好..找到了!!! 网上的那些东西真心看了更闹心,因为还没解决... 原因一.访问路径确实错了,导致Dispatcher找不到给你传达的地方,修改下领 ...

  9. Shell - 简明Shell入门

    本文以示例和注释的方式,对Shell编程的基本知识点进行了总结和回顾,所有脚本均已做了基本的调试和验证. Shell - 简明Shell入门 01 - 第一个脚本 脚本的定义.执行方法以及echo命令 ...

  10. JS 数据类型和数据分析

    栈区:(stack)-由编译器自动分配释放,存放函数的参数值,局部变量的值等. 特点是存放体积小,使用频率高的数据.可以类比内存. 堆区:(heap)-一般由程序员分配释放,若开发者不释放,程序结束时 ...