迭代器模式
1、概要
在面向对象编程中,迭代器模式是一种很常见的设计模式:它可以让用户透过特定的接口巡访容器中的每一个元素而不用了解底层的实现。就好像我们在使用集合的时候并不需要关注其底层实现是数组,链表或是其它数据结构,我们可以使用相同的方式去遍历集合中的元素而不暴露其内部结构,是不是感觉迭代器模式就是为了容器而生的!
目的:迭代器模式提供了一种顺序遍历聚合对象元素而不用暴露其内部结构的方式
2、实现
从类图可以看到迭代器的各个角色:主要是基于两个接口,然后通过其成对的实现类来实现,因此每一个具体容器对象都会聚合到关联的迭代器对象。具体类的功能如下:
- Aggregate(抽象容器):是一个接口,具体容器都需要实现的接口,声明返回迭代器的方法
- Iterator(抽象迭代器):是一个接口,具体迭代器都需要实现的接口,声明了迭代器的基本方法
- ConcreteAggregate(具体容器):实现抽象容器的具体实现类,返回具体的迭代器对象
- ConcreteIterator(具体迭代器):实现抽象迭代器的具体实现类,聚合了具体容器对象且根据其数据结构实现迭代逻辑
3 、示例
- 定义容器抽象接口
package cn.blog.eight;
/**
* @author lin
* @version V1.0
*/
public interface MyCollection<T> {
//定义集合大小
public int size();
//定义集合添加方法
public boolean add(T t);
//定义集合元素获取方法
public T get(int i);
//定义集合获取迭代器方法
public MyIterator<T> iterator();
}
定义了一个抽象容器MyCollection,用于规范容器的实现类。提供了操作集合基本方法如注释,且声明返回迭代器对象方法。
- 定义迭代器抽象接口
package cn.blog.eight;
/**
* @author lin
* @version V1.0
*/
public interface MyIterator<T> {
//获取当前游标前一位元素的值
public T previous();
//游标后移一位且获取当前游标的值
public T next();
//判断后一位元素是否存在
public boolean hasNext();
}
定义了一个抽象迭代器MyIterator。声明了迭代器的基本功能,功能如注释。
- 具体容器实现
package cn.blog.eight;
import java.util.ArrayList;
import java.util.List;
/**
* @author lin
* @version V1.0
*/
public class MyList<T> implements MyCollection<T> {
private final List<T> list = new ArrayList<>();
@Override
public int size() {
return list.size();
}
@Override
public boolean add(T t) {
return list.add(t);
}
@Override
public T get(int i) {
return list.get(i);
}
@Override
public MyIterator<T> iterator() {
return new MyListIterator<>(this);
}
@Override
public String toString() {
return "MyList{" +
"list=" + list +
'}';
}
}
具体容器的实现类,可以看到底层实现是ArrayList,里面实现的增删查改方法也是从ArrayList偷过来的…
- 具体迭代器实现
package cn.blog.eight;
import java.util.NoSuchElementException;
/**
* @author lin
* @version V1.0
*/
public class MyListIterator<T> implements MyIterator<T> {
private final MyList<T> list;
private int cursor = -1;
public MyListIterator(MyList<T> list) {
this.list = list;
}
@Override
public T previous() {
int i = cursor;
if (cursor > 0) {
return list.get(--i);
} else {
return (T) "为容器首项,没有前元素";
}
}
@Override
public T next() {
if (cursor < list.size() - 1) {
return list.get(++cursor);
}
throw new NoSuchElementException("集合越界!");
}
@Override
public boolean hasNext() {
return cursor < list.size() - 1;
}
}
实现了Iterator接口,聚合了MyList对象,完成了对其的遍历操作。
- 测试
package cn.blog.eight;
/**
* @author lin
* @version V1.0
*/
public class Main {
public static void main(String[] args) {
MyCollection<String> coll = new MyList<>();
coll.add("aa");
coll.add("bb");
coll.add("cc");
coll.add("dd");
MyIterator<String> it = coll.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println("当前元素:" + s);
System.out.println(s + "元素前一个元素为:" + it.previous());
}
System.out.println(coll);
}
}
我们并不知道MyCollection的底层实现是如何的,但能直接使用迭代器对象对其进行遍历。因此我们后面有新的需求新增了成对的抽象容器实现类和抽象迭代器实现类,也可以使用此方式进行元素的遍历。其实Java集合中的迭代器模式和这个示例也是大同小异的,不同的集合对象底层的数据结构不同所以他们的迭代器实现逻辑也有一定的差异,但对于我们使用是无感的,具体实现可查看源码分析。
- 结果
当前元素:aa
aa元素前一个元素为:为容器首项,没有前元素
当前元素:bb
bb元素前一个元素为:aa
当前元素:cc
cc元素前一个元素为:bb
当前元素:dd
dd元素前一个元素为:cc
MyList{list=[aa, bb, cc, dd]}