码迷,mamicode.com
首页 > 其他好文 > 详细

迭代器模式

时间:2016-05-10 02:23:51      阅读:263      评论:0      收藏:0      [点我收藏+]

标签:

1、什么是迭代器呢?

  迭代器是一种取出元素的方式,也就是遍历某一元素集合内元素的方式。我们平常对于数组的遍历方式是通过下角标利用for循环等来操作数据,元素集合不止数组一种,例如还有ArrayList(底层为数组)、LinkedList(底层为链表)、HashSet(使用hash表)等,每一个集合内部的存储结构都是不同的,所以每一个集合存和取都是不一样,那么针对这些集合遍历就要分别使用对应的遍历方式。


  那么,有没有一个统一的解决方案来处理这样的循环遍历问题呢?我们只提供一种模式就能够遍历所有的不同数据结构的集合,而且还不能够暴露集合内部的表示(即不用知道内部实现细节到底是数组还是ArrayList、LinkedList,这样就不必在外部应用中暴露获得元素的方式),这就需要迭代器设计模式闪亮登场了。


  迭代器模式的出现统一了数据循环遍历的问题,让我们不再关心软件系统内部的实现细节,按照统一的模式顺序访问一个集合对象中的各个元素。


2、迭代器模式的方式?


  因为每个集合对象本身不一样,所以当我们对不同类型的集合进行遍历时,由于必须暴露其内部表示,因此所写的遍历语句(for)是不能通用的。如果我们对需要用到的集合创建一个迭代器,由于对迭代器的遍历语句是相同的,那么就可以实现遍历语句的通用性。另外,拥有了迭代器就意味着我们对集合的实现方式是完全不知道的,即不必知道集合内部的实现细节,以后一旦需要改变集合的实现,例如从数组改为ArrayList,客户端的代码是不需要发生任何改变的,甚至于客户端根本就不知道所遍历的集合发生了改变。


  对于遍历的方式,首先谈一下Java语言内置的迭代器,即集合中的迭代器,其是耦合在集合对象内部,让容器实现遍历功能,这种方式应用在Java集合的底层代码实现中;


  Java语言内置的迭代器是在外面定义一个迭代器的接口Iterator,这样所有的集合在其内部定义迭代器时统一实现该接口,这样所有集合内部都有了自己的迭代器,单列集合的根接口Collection中定义一个获取迭代器的方法public Iterator iterator()专门用于获取其迭代器对象,这样所有实现Collection接口的实现类中只需要重写该iterator方法,返回自己的迭代器对象即可。


  这种方式存在一定的弊端:首先,将遍历算法耦合在集合对象内部,这就加重了几何对象的负担,不但需要处理数据的添加、删除和修改,还要负责数据的遍历,显然,集合对象的负担过重,这也是不符合单一职责原则的。


  另外一种方式就是今天我们需要讲的一种方式:


技术分享


  这需要满足以下两点内容:

    (1)迭代器在不需要暴露集合对象内部实现细节的情况下,能够遍历集合中的数据;

    (2)迭代器获取集合对象内部数据的方式,也不需要依赖于集合对象下标,即生成迭代器之后,就完全脱离集合对象的约束。


  在迭代器的遍历过程中,我们没有暴露集合类的内部细节内容,而是返回object类型,而遍历方法也是不需要任何下标信息的,因为我们可以在迭代器内部获得集合对象的引用,可以默认下标从-1开始,在遍历方法中顺序变化,从而获得集合对象内部元素内容。这样,就有效的将迭代器与集合对象分离开,使两者从产生迭代器之后就各不相干,而客户端调用只与迭代器遍历相关,不再依赖于集合对象的内部细节。


  迭代器建模图:


技术分享


3、迭代器模式案例?


  需求:对人员信息使用迭代器模式进行遍历。

  (1)首先得到人员信息接口,里面只有一个获得人员信息的方法:


<span style="font-size:18px;">package 迭代器模式;
/**
 * 需求:人员信息接口
 * 		方法:获得人员信息
 * @author win2016
 *
 */
public interface IPerson {
	//获得人员信息方法
	public String getPersonInfo();
}</span>

  (2)人员信息类,用于存储人员的基本信息:


<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>

  (4)人员集合实现:


<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>

  (5)迭代器接口:


<span style="font-size:18px;">package 迭代器模式;
/**
 * 需求:迭代器接口
 * 方法:判断是否存在下一个元素;获取下一个元素方法;删除方法
 * @author win2016
 *
 */
public interface Iterator1 {
	//判断是否有下一个节点
	public boolean hasNext();
	//获得下一个节点对象
	public Object next();
	//删除方法
	public Object remove();
}</span>

  (6)迭代器实现类:


<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>


  (7)测试类:


<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集合。

  那么,迭代器如何面对变化呢?

    现在我们假设人员列表信息类型改变了,使用数组类型而不是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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!