从Java Collections源码分析迭代器模式

一、 引言
  
  迭代这个名词对于熟悉Java的人来说绝对不陌生。我们常常使用JDK提供的迭代接口进行java collection的遍历:

  
  Iterator it = list.iterator();
  while(it.hasNext()){
  //using “it.next();”do some businesss logic
  }
  
  而这就是关于迭代器模式应用很好的例子。
  
  二、 定义与结构
  
  迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象各个元素,而又不需暴露该对象的内部细节

  
  从定义可见,迭代器模式是为容器而生。很明显,对容器对象的访问必然涉及到遍历算法。你可以一股脑的将遍历方法塞到容器对象中去;或者根本不去提供什么遍历算法,让使用容器的人自己去实现去吧。这两种情况好像都能够解决问题。
  
  然而在前一种情况,容器承受了过多的功能,它不仅要负责自己“容器”内的元素维护(添加、删除等等),而且还要提供遍历自身的接口;而且由于遍历状态保存的问题,不能对同一个容器对象同时进行多个遍历。第二种方式倒是省事,却又将容器的内部细节暴露无遗。
  
  而迭代器模式的出现,很好的解决了上面两种情况的弊端。先来看下迭代器模式的真面目吧。
  
  迭代器模式由以下角色组成:
  
  1) 迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的接口。
  
  2) 具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。
  
  3) 容器角色(Container):容器角色负责提供创建具体迭代器角色的接口。
  
  4) 具体容器角色(Concrete Container):具体容器角色实现创建具体迭代器角色的接口——这个具体迭代器角色于该容器的结构相关。
  
  迭代器模式的类图如下:

 

迭代器模式类图

 

  

  三、 从Java Collections源码分析迭代器模式


  下面我们拿出java中Iterator的源码相关源码进行分析。

  下图是Java Collections的整体关系图:

 

Java Collection

 

  从图中很容易看出,Collection和代表相应的抽象容器角色,而Iterator和ListIterator则代表相应的抽象迭代器角色。

  其中ListIterator是Iterator的子接口,扩充了向后遍历的方法接口。

  以下是Collection,Iterator,List及ListIterator的代码片段:

Collection:

 

Iterator:

 

List:

 

ListIterator:

 

  那么具体容器角色和具体迭代器角色是那些类呢?

  首先先从Iterator入手,让我们先回到图上,熟悉Java Collections框架的朋友很容易明白Collection的实现类很多,它是Java Collections框架的顶层结构,它的下层又分Set和List两个分支,那我们就分别来分析这两个分支具体的具体实现。


  List的第一级实现类为AbstractList,java在此类中实现了具体容器角色和具体迭代器角色,那如何能在一个类中实现两个角色呢,还是从代码入手吧:

      对于再下层的实现类,可以灵活的重写生产方法,并实现专用的迭代器内部类。

 

  Set和List不同,它的下一层没有实现类,而是俩个接口(AbstractSet和SortedSet),再往下一层找便是我们熟悉的两个实现类HashSet和TreeSet,而了解Java Collection的读者会知道,HashSet和TreeSet其实是借助Map系的HashMap和TreeMap实现的,所以具体实现方法是在Map系中的实现类中实现的(隐藏够深的)。因为涉及的两个对象数据结构稍微有些复杂(散列表和红黑树),可以在此处了解其内部构造。废话少说,上代码:

 

  TreeSet的迭代器实现和HashMap很相似,在这里就不再罗嗦了,有兴趣的读者可以去研读一下源码。

      对于再下层的实现类,可以灵活的重写生产方法,并实现专用的迭代器内部类。

 

  三、 总结


  从代码我们可以得出以下几点:

      1.具体容器角色和具体迭代器角色因为是紧耦合关系,在具体容器中使用内部类将具体迭代器实现是一个很好的做法,方便了具体迭代器直接访问具体容器的所有细节。

      2.内部类为私有,既实现类具体迭代器,又使此容器的专用迭代器对外不可见,迫使使用者进行接口编程。

          3.使用迭代器访问一个容器对象的内容而无需暴露它的内部表示。

          4.对同一个容器对象,可以同时进行多个遍历。

          5.支持以不同的方式遍历一个容器角色。根据实现方式的不同,效果上会有差别。

          6.简化了容器的接口。但是在java Collection中为了提高可扩展性,容器还是提供了遍历的接口。

          7.为遍历不同的容器结构提供一个统一的接口。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值