Java设计模式及应用场景之《迭代器模式》

文章目录

      • 一、迭代器模式定义
      • 二、迭代器模式的结构和说明
      • 三、迭代器模式示例
      • 四、增强for循环原理
      • 五、迭代器模式的优缺点
      • 六、迭代器模式的应用场景
      • 七、模式说明

一、迭代器模式定义

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
(提供一种方法顺序访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。)

二、迭代器模式的结构和说明

Java设计模式及应用场景之《迭代器模式》_第1张图片

  • IterableCollection 集合接口。 所要遍历的集合的接口,实现了该接口的类将成为一个可以保存多个元素的集合,类似数组。并且提供方法来获取与集合兼容的迭代器,一般JDK自带的容器中,提供的是 iterator() 方法。
  • ConcreteCollection 具体集合对象。 实现创建相应的迭代器的方法。
  • Iterator 迭代器接口。 负责定义访问和遍历元素的接口方法。
  • ConcreteIterator 具体的迭代器对象。 实现迭代器接口中定义的访问和遍历元素的方法。

三、迭代器模式示例

假设我们需要提供一个接收集合参数的方法,在方法中会对这个集合中的内容进行遍历操作,拿我们常用的List来示意,我们一般可以这样遍历

/**
 * 操作集合的方法
 * @param list
 */
public void operation(List<String> list){
     
	
	for(int i=0; i<list.size(); i++){
     
		System.out.println(list.get(i));
	}

	// do something
}

一般情况下,我们都是使用简单列表存储元素。 但有些集合还会使用栈、 树、 图和其他复杂的数据结构。如果我们这个方法,想要接收处理这么多集合类型的数据,该怎么处理呢。

很多人都会想到,我们可以将方法参数类型改为Collection,这样可以接收很多类型的集合数据。那么,我们来改下试试。
Java设计模式及应用场景之《迭代器模式》_第2张图片
Collection接口中没有get(i)这个方法~,这就尴尬了,那咋整,哎,有人会说,我们可以用增强for循环啊!

嗯,是的,增强for循环是可以解决这个遍历的问题,代码示意如下

/**
 * 操作集合的方法
 * @param collection
 */
public void operation(Collection<String> collection){
     

	for(String str : collection){
     
		System.out.println(str);
	}

	// do something
}

增强for循环之所以能实现遍历是有原因的,原理我们放到后边再说,这里先跟大家展示下通过迭代器的方式来进行遍历。

/**
 * 操作集合的方法
 * @param collection
 */
public void operation(Collection<String> collection){
     

	// 创建迭代器对象
	Iterator<String> iterator = collection.iterator();

	// 通过迭代器对象,遍历集合中的元素
	while(iterator.hasNext()){
     
		System.out.println(iterator.next());
	}

	// do something
}

使用迭代器也很容易的解决了我们所遇到的问题。

以ArrayList为例,我们看看迭代器的原理是怎样的。

ArrayList - -> List 一> Collection 一> Iterable

ArrayLisy类实现了List接口,List接口继承Collection接口,Collection接口继承Iterable接口,在Iterable接口中,声明了一个创建迭代器的方法iterator()

public interface Iterable<T> {
     
    /**
     * 创建迭代器的方法声明
     */
    Iterator<T> iterator();

}

ArrayLisy 中最终实现 iterator() 方法,返回一个新创建的Itr对象。

public Iterator<E> iterator() {
     
	return new Itr();
}

Itr 是 ArrayLisy 类中定义的,实现了 Iterator 接口的内部类 。Itr 类中实现了 hasNext() 方法和 next() 方法的具体业务逻辑。

private class Itr implements Iterator<E> {
     
	int cursor;       // index of next element to return
	int lastRet = -1; // index of last element returned; -1 if no such

	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];
	}
	...
}

hasNext() 方法判断是否有下一个元素,如果有,通过next() 方法取出,这样就实现了对 ArrayLisy 集合中元素的遍历操作。

如果我们使用的是 HashSet 而不是 ArrayLisy ,原理其实是一样的。

Java设计模式及应用场景之《迭代器模式》_第3张图片

四、增强for循环原理

前面,我们提到可以通过增强for循环对集合进行遍历,这里我们剖析一下,这种增强for循环底层是如何实现的。

我们对如下代码进行反编译

/**
 * 操作集合的方法
 * @param collection
 */
public void operation(Collection<String> collection){
     

	for(String str : collection){
     
		System.out.println(str);
	}

	// do something
}

反编译后

public void operation(Collection<String> collection) {
     
	Iterator var2 = collection.iterator();

	while(var2.hasNext()) {
     
		String str = (String)var2.next();
		System.out.println(str);
	}

}

通过反编译,我们看到,增强for循环遍历集合是通过迭代器模式来实现的。

除了集合,增强for循环还可以遍历数组,数组中是没办法使用迭代器模式的,那遍历数组的增强for循环又是怎么实现的呢?

/**
 * 操作集合的方法
 * @param Strs
 */
public void operation(String[] Strs){
     

	for(String str : Strs){
     
		System.out.println(str);
	}

	// do something
}

反编译后

public void operation(String[] Strs) {
     
	String[] var2 = Strs;
	int var3 = Strs.length;

	for(int var4 = 0; var4 < var3; ++var4) {
     
		String str = var2[var4];
		System.out.println(str);
	}

}

反编译后,我们其实可以看到,通过增强for循环对数组进行遍历,其实就是使用了最普通的索引下标的遍历方式。

综上,归纳起来,增强for循环原理就这两点:

  • 对于数组,使用索引下标遍历;
  • 对于集合,使用迭代器模式遍历。

五、迭代器模式的优缺点

优点

  • 访问一个聚合对象时,无需暴露该聚合对象的内部表示,从而提高聚合对象的封装性。
  • 迭代器模式使得聚合内容和迭代算法分离,这样就可以通过不同的迭代器对象、不同的遍历方式来遍历一个对象。如单向迭代、双向迭代、翻页迭代等。
  • 迭代器为遍历不同的聚合对象提供了一个统一的迭代接口,从而简化了客户端的调用。

缺点

  • 如果你的程序只与简单的集合进行交互, 应用该模式可能会矫枉过正。
  • 对于某些集合,如ArrayList, 使用迭代器可能比直接遍历的效率低。

六、迭代器模式的应用场景

  • 当集合内部为复杂的数据结构, 且你希望对客户端隐藏其复杂性时,可以使用迭代器模式。
  • 如果希望有多种遍历方式可以访问聚合对象,可以使用迭代器模式。
  • 如果希望不同的聚合对象有一个统一的遍历接口,可以使用迭代器模式。

七、模式说明

java 中已经把迭代器运用到各个聚集类( collection)中了,使用 java 自带的迭代器就已经满足我们的需求了。不过了解了迭代器模式,可以帮助我们更好的理解Java的一些源码实现。

你可能感兴趣的:(Java设计模式,设计模式,Java设计模式,迭代器模式,Java迭代器模式,增强for循环原理)