博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一起学设计模式 - 迭代器模式
阅读量:6699 次
发布时间:2019-06-25

本文共 5526 字,大约阅读时间需要 18 分钟。

迭代器模式(Iterator Pattern)属于行为型模式的一种,提供一种方法访问一个容器中各个元素,而又不需要暴露该对象的内部细节。

<!-- more -->

概述

迭代器模式听起来可能感觉很陌生,但是实际上,迭代器模式是所有设计模式中最简单也是最常用的设计模式,正是因为太常用了,所以导致很多人忽略了它的存在。

在实际的开发过程中,我们可能需要针对不同的需求,可能需要以不同的方式来遍历整个整合对象,但又不希望在聚合对象的抽象接口层中充斥着各种不同的便利操作。这个时候我们就需要这样一种东西,它应该具备如下三个功能:

  • 能够便利一个聚合对象。
  • 我们不需要了解聚合对象的内部结构。
  • 能够提供多种不同的遍历方式。

迭代器模式: 把在元素之间游走的责任交给迭代器,而不是聚合对象。简化了聚合的接口和实现,让聚合更专注在它所应该专注的事情上,这样做更加符合单一责任原则。

UML结构图

迭代器模式UML结构图

模式结构

  • Iterator(抽象迭代器): 具体迭代器需要实现的接口,提供了游走聚合对象元素之间的方法
  • ConcreteIterator(具体迭代器): 对具体的聚合对象进行遍历,每一个聚合对象都应该对应一个具体的迭代器。
  • Aggregate(抽象聚合类): 存储和管理元素对象,声明了createIterator()用于创建一个迭代器对象,充当抽象迭代器工厂角色
  • ConcreteAggregate(具体聚合类): 实现了在抽象聚合类中声明的createIterator(),该方法返回一个与该具体聚合类对应的具体迭代器ConcreteIterator实例。

案例

UML图如下:

UML图

1.先定义抽象迭代器``

interface Iterator
{ //判断是否有还有下一个元素 boolean hasNext(); //取出下一个对象 E next();}

2.在定义一个具体迭代器对象,实现了Iterator中的方法

class MusicIterator
implements Iterator
{ private E[] es; private int position = 0; public MusicIterator(E[] es) { this.es = es; } @Override public boolean hasNext() { return position != es.length; } @Override public E next() { E e = es[position]; position += 1; return e; }}

3.接下来定义抽象聚合类(常为 Collection , List , Set 等)

interface AbstractList
{ void add(E e); Iterator
createIterator();}

4.最后创建具体聚合类 (常为 ArrayList , HashSet 等,是抽象聚合类的实现类)

class MusicList implements AbstractList
{ private String[] books = new String[5]; private int position = 0; @Override public void add(String name) { books[position] = name; position += 1; } @Override public Iterator
createIterator() { return new MusicIterator<>(books); }}

5.创建测试工程

public class Client {    public static void main(String[] args) {        AbstractList
list = new MusicList(); list.add("凉凉"); list.add("奇谈"); list.add("红颜"); list.add("伴虎"); list.add("在人间"); Iterator
iterator = list.createIterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } }}

6.运行效果

凉凉奇谈红颜伴虎在人间

至此一个简单的迭代器就完成了,实现了对容器的遍历。可以看到迭代器在Client中遍历时根本不需要知道他底层的实现,只需要通过迭代器来遍历就可以了。

JDK中应用

上文介绍了自己实现一个简单的迭代器,看完的应该就不陌生了,它其实在JAVA的很多集合类中被广泛应用,接下来看看JAVA源码中是如何使用迭代器模式的。

List
list = new ArrayList<>();Iterator
iterator = list.iterator();while (iterator.hasNext()) { System.out.println(iterator.next());}

看完这段代码是不是很熟悉,与我们上文代码基本类似

  • List:抽象聚合器
  • ArrayList:具体的聚合类
  • Iterator:抽象迭代器
  • list.iterator():返回的是实现了Iterator接口的具体迭代器对象

接下来看下ArrayList中的iterator是如何实现的

public Iterator
iterator() { return new Itr();}private class Itr implements Iterator
{ int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer
consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }}

这部分代码还是比较简单,大致就是在iterator方法中返回了一个实例化的Iterator对象。Itr是一个内部类,它实现了Iterator接口并实现了其中的方法。

当我们在使用JAVA开发的时候,想使用迭代器模式的话,只要让我们自己定义的容器类实现java.util.Iterable并实现其中的iterator方法使其返回一个java.util.Iterator的实现类就可以了。

总结

迭代器模式与集合共生共死的,一般来说,我们只要实现一个集合,就需要同时提供这个集合的迭代器,就像java中的Collection,List、Set、Map等,这些集合都有自己的迭代器。假如我们要实现一个这样的新的容器,当然也需要引入迭代器模式,给我们的容器实现一个迭代器。但在绝大多数情况,我们是不需要自己实现的,基本都内置了

优点

  • 支持不同方式遍历一个聚合对象,在同一个聚合上可以有多个遍历。
  • 简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再自行提供数据遍历等方法。
  • 在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码

缺点

  • 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
  • 抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展,例如JDK内置迭代器Iterator就无法实现逆向遍历,如果需要实现逆向遍历,只能通过其子类ListIterator等来实现,而ListIterator迭代器无法用于操作Set类型的聚合对象。在自定义迭代器时,创建一个考虑全面的抽象迭代器并不是件很容易的事情。

说点什么

全文代码:

  • 个人QQ:1837307557
  • battcn开源群(适合新手):391619659

微信公众号:battcn(欢迎调戏)

福利

关注公众号:battcn,回复springboot即可获得 <Spring Boot从入门到实战 基础实战系列教程全集><2017最新spring boot 外卖实战微信公众平台视频教程>

转载地址:http://fpwlo.baihongyu.com/

你可能感兴趣的文章
linux LVM 逻辑卷组管理
查看>>
Linux分区类型EXT2、EXT3、EXT4详解
查看>>
图像识别DM8127开发攻略——开发环境搭建
查看>>
idea 设置选中代码得背景颜色
查看>>
Javascript跨域后台设置拦截
查看>>
Office协同办公:SkyDrive
查看>>
稳扎稳打Silverlight(17) - 2.0数据之详解DataGrid, 绑定数据到ListBox
查看>>
Window下部署Maven Nexus
查看>>
Window.Open详解
查看>>
Python将数据库数据导入到EXCEL
查看>>
android api 中文 (73)—— AdapterView
查看>>
CHECKSUM/BINARY_CHECKSUM 和 HASHBYTES 的选择
查看>>
mono 最近的三条消息
查看>>
虚拟机与主机建立共享目录
查看>>
第六章apache目录文件的位置及作用
查看>>
Lync Server 2010迁移至Lync Server 2013部署系列 Part10:配置存档、监控服务器
查看>>
技术分享连载(三十)
查看>>
ResultSet can not re-read row data for column X的解决方法
查看>>
Android:线程间通讯的其他方法、runOnUiThread(action)、Handler.post(action)、post
查看>>
Badboy自动化测试工具3 创建suites,tests,steps和Template
查看>>