标签:
迭代器是一种取出元素的方式,也就是遍历某一元素集合内元素的方式。我们平常对于数组的遍历方式是通过下角标利用for循环等来操作数据,元素集合不止数组一种,例如还有ArrayList(底层为数组)、LinkedList(底层为链表)、HashSet(使用hash表)等,每一个集合内部的存储结构都是不同的,所以每一个集合存和取都是不一样,那么针对这些集合遍历就要分别使用对应的遍历方式。
那么,有没有一个统一的解决方案来处理这样的循环遍历问题呢?我们只提供一种模式就能够遍历所有的不同数据结构的集合,而且还不能够暴露集合内部的表示(即不用知道内部实现细节到底是数组还是ArrayList、LinkedList,这样就不必在外部应用中暴露获得元素的方式),这就需要迭代器设计模式闪亮登场了。
迭代器模式的出现统一了数据循环遍历的问题,让我们不再关心软件系统内部的实现细节,按照统一的模式顺序访问一个集合对象中的各个元素。
因为每个集合对象本身不一样,所以当我们对不同类型的集合进行遍历时,由于必须暴露其内部表示,因此所写的遍历语句(for)是不能通用的。如果我们对需要用到的集合创建一个迭代器,由于对迭代器的遍历语句是相同的,那么就可以实现遍历语句的通用性。另外,拥有了迭代器就意味着我们对集合的实现方式是完全不知道的,即不必知道集合内部的实现细节,以后一旦需要改变集合的实现,例如从数组改为ArrayList,客户端的代码是不需要发生任何改变的,甚至于客户端根本就不知道所遍历的集合发生了改变。
对于遍历的方式,首先谈一下Java语言内置的迭代器,即集合中的迭代器,其是耦合在集合对象内部,让容器实现遍历功能,这种方式应用在Java集合的底层代码实现中;
Java语言内置的迭代器是在外面定义一个迭代器的接口Iterator,这样所有的集合在其内部定义迭代器时统一实现该接口,这样所有集合内部都有了自己的迭代器,单列集合的根接口Collection中定义一个获取迭代器的方法public Iterator iterator()专门用于获取其迭代器对象,这样所有实现Collection接口的实现类中只需要重写该iterator方法,返回自己的迭代器对象即可。
这种方式存在一定的弊端:首先,将遍历算法耦合在集合对象内部,这就加重了几何对象的负担,不但需要处理数据的添加、删除和修改,还要负责数据的遍历,显然,集合对象的负担过重,这也是不符合单一职责原则的。
另外一种方式就是今天我们需要讲的一种方式:
这需要满足以下两点内容:
(1)迭代器在不需要暴露集合对象内部实现细节的情况下,能够遍历集合中的数据;
(2)迭代器获取集合对象内部数据的方式,也不需要依赖于集合对象下标,即生成迭代器之后,就完全脱离集合对象的约束。
在迭代器的遍历过程中,我们没有暴露集合类的内部细节内容,而是返回object类型,而遍历方法也是不需要任何下标信息的,因为我们可以在迭代器内部获得集合对象的引用,可以默认下标从-1开始,在遍历方法中顺序变化,从而获得集合对象内部元素内容。这样,就有效的将迭代器与集合对象分离开,使两者从产生迭代器之后就各不相干,而客户端调用只与迭代器遍历相关,不再依赖于集合对象的内部细节。
迭代器建模图:
需求:对人员信息使用迭代器模式进行遍历。
(1)首先得到人员信息接口,里面只有一个获得人员信息的方法:
<span style="font-size:18px;">package 迭代器模式; /** * 需求:人员信息接口 * 方法:获得人员信息 * @author win2016 * */ public interface IPerson { //获得人员信息方法 public String getPersonInfo(); }</span>
<span style="font-size:18px;">package 迭代器模式; /** * 需求:人员类 * * @author win2016 * */ public class Person implements IPerson { //姓名 private String name; //年龄 private int age; //性别 private int sex; //构造方法传入值 public Person(String name,int age,int sex){ this.name = name; this.age = age; this.sex = sex; } //获取人员信息 @Override public String getPersonInfo() { return "姓名:"+this.name+"-年龄"+this.age+"-性别"+(this.sex==1?"男":(this.sex==0?"女":"")); } }</span>
(3)人员集合接口,有两个方法,一个是获得人员内部信息列表方法,一个是获得迭代器接口方法,设置两种方法是为了在客户端应用中分别使用,便于比较。
<span style="font-size:18px;">package 迭代器模式; import java.util.ArrayList; /** * 需求:人员集合接口 获得内部存储人员信息内容 * 方法:获得人员内部信息列表方法;获得迭代器接口方法(目的:在客户端应用中分别使用) * @author win2016 * */ public interface IPersonList { //获得内部存储人员信息内容 public ArrayList<IPerson> getPersonList(); //迭代器 public Iterator1 iterator(); }</span>
<span style="font-size:18px;">package 迭代器模式; import java.util.ArrayList; import java.util.Iterator; import java.util.Random; /** * 需求:人员集合实现类 * 在PersonList的构造方法中初始化人员信息列表内容 * * @author win2016 * */ public class PersonList implements IPersonList { //存储用户信息集合 private ArrayList<IPerson> list = new ArrayList<IPerson>(); //构造方法初始化人员信息 public PersonList(){ Random random = new Random(); //创建人员信息 for (int i = 0; i < 6; i++) { IPerson person = new Person("人员"+i,random.nextInt(30),random.nextInt(2)); //存入集合 list.add(person); } } //获得内部人员信息 public ArrayList<IPerson> getPersonList(){ return this.list; } //迭代器 public Iterator1 iterator(){ return new PersonIterator(this.list); } }</span>
<span style="font-size:18px;">package 迭代器模式; /** * 需求:迭代器接口 * 方法:判断是否存在下一个元素;获取下一个元素方法;删除方法 * @author win2016 * */ public interface Iterator1 { //判断是否有下一个节点 public boolean hasNext(); //获得下一个节点对象 public Object next(); //删除方法 public Object remove(); }</span>
<span style="font-size:18px;">package 迭代器模式; import java.util.ArrayList; /** * 需求:迭代器实现类 * * @author win2016 * */ public class PersonIterator implements Iterator1 { //存储人员列表对象信息 private final ArrayList<IPerson> personList; //存储位置信息,初始值为-1 private int index = -1; //构造方法将人员列表对象传入 public PersonIterator(ArrayList<IPerson> personList){ this.personList = personList; } //是否有下一个元素 @Override public boolean hasNext() { return (this.personList == null? false:(index<this.personList.size()-1)); } //获得下一个元素对象 @Override public Object next() { return this.personList.get(++index); } //删除对象 @Override public Object remove() { if (this.personList != null) { return this.personList.remove(index); } return null; } }</span>
<span style="font-size:18px;">package 迭代器模式; /** * 需求:测试类 * @author win2016 * */ public class Test { public static void main(String[] args) { //创建人员列表对象 IPersonList personList = new PersonList1(); System.out.println("--------使用迭代器输出人员信息----------"); //生成迭代器 Iterator1 iterator = personList.iterator(); //循环迭代器,遍历每一个元素输出人员信息 while(iterator.hasNext()){ //获得人员对象实例 IPerson person = (IPerson) iterator.next(); if (person!=null) { //输出人员信息 System.out.println(person.getPersonInfo()); } } } }</span>
那么,迭代器如何面对变化呢?
现在我们假设人员列表信息类型改变了,使用数组类型而不是ArrayList,该如何处理呢?我们只要增加一个用数组实现的PersonList1:
<span style="font-size:18px;">package 迭代器模式; import java.util.ArrayList; import java.util.Random; /** * 需求:数组类型 * @author win2016 * */ public class PersonList1 implements IPersonList { //存储用户信息列表 private final IPerson[] list = new IPerson[6]; //构造方法初始化人员信息 public PersonList1(){ Random random = new Random(); //创建人员信息 for (int i = 0; i < 6; i++) { IPerson person = new Person("人员"+i, random.nextInt(30), random.nextInt(2)); list[i] = person; } } //迭代器 public Iterator1 iterator(){ return new ArrPersonIterator(this.list); } //获得内部存储人员信息内容 public IPerson[] getPersonInfo() { return list; } @Override public ArrayList<IPerson> getPersonList() { // TODO Auto-generated method stub return null; } }</span>
<span style="font-size:18px;">package 迭代器模式; /*** * 需求:数组迭代器 * * @author win2016 * */ public class ArrPersonIterator implements Iterator1 { //私有属性存储人员列表对象信息 private final IPerson[] personList; //存储位置信息,初始值为-1 private int index = -1; //构造方法将人员列表对象存入 public ArrPersonIterator(IPerson[] personList){ this.personList = personList; } //判断是否有下一个节点 public boolean hasNext(){ return (this.personList == null?false:(index<this.personList.length-1)); } //获取下一个节点元素 public Object next(){ if (this.personList!=null&&(index<this.personList.length-1)) { //获得人员列表对象中的人员信息 return this.personList[++index]; } return null; } //删除对象 public Object remove(){ if (this.personList!=null) { IPerson person = this.personList[index]; this.personList[index] = null; return person; } return null; } }</span>
总结:当你需要访问一个聚合对象,而且不管这些对象是什么都需要遍历的时候,就应该考虑使用迭代器模式。另外,当需要对聚集有多种方式遍历时,可以考虑去使用迭代器模式。迭代器模式为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口。
标签:
原文地址:http://blog.csdn.net/fightfaith/article/details/51356408