一、介绍,定义
这个模式对开发者来说几乎不会自己去实现一个迭代器。所以对于这个模式更多的是在于理会其思想,而非应用。
提供一种方法顺序访问一个容器对象中的各个元素,而又不需要暴露该对象的内部表示。
二、使用场景
遍历一个容器对象
三、UML类图

Iterator : 迭代器接口,负责定义、访问、遍历元素的接口。
ConcreteIterator:具体的迭代类,实现迭代器接口,并记录遍历的当前位置。
Aggregate:容器接口,负责提供创建具体迭代器的接口。
ConcreteAggregate:具体容器类,和具体迭代器相关联。
四、通用代码
/**
* 迭代器接口:负责定义、访问和遍历元素的接口
* @param <T>
*/
public interface Iterator<T> {
/**
* 是否还有下一个对象
* @return true:有; false:没有
*/
boolean hasNext();
/**
* @return 返回当前位置的元素并将位置移至下一位
*/
T next();
}
/**
* 具体迭代器类:实现迭代器接口,并记录遍历的当前位置
*
* @param <T>
*/
public class ConcreteIterator<T> implements Iterator<T> {
private List<T> list = new ArrayList<T>();
private int cursor = 0;
public ConcreteIterator(List<T> list) {
super();
this.list = list;
}
@Override
public boolean hasNext() {
return cursor != list.size();
}
@Override
public T next() {
T obj = null;
if (this.hasNext()) {
obj = this.list.get(cursor++);
}
return obj;
}
}
/**
* 容器接口:负责提供创建具体迭代器角色的接口
*
* @param <T>
*/
public interface Aggregate<T> {
/**
* 添加一个元素
*
* @param obj
* 元素对象
*/
void add(T obj);
/**
* 移除一个元素
*
* @param obj
* 元素对象
*/
void remove(T obj);
/**
* 获取容器的迭代器
*
* @return 迭代器对象
*/
Iterator<T> iterator();
}
/**
* 具体容器类:具体迭代器角色与该容器相关联
*
* @param <T>
*/
public class ConcreteAggregate<T> implements Aggregate<T> {
private List<T> list = new ArrayList<>();
@Override
public void add(T obj) {
list.add(obj);
}
@Override
public void remove(T obj) {
list.remove(obj);
}
@Override
public Iterator<T> iterator() {
return new ConcreteIterator<>(list);
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
Aggregate<String> a = new ConcreteAggregate<>();
a.add("hello1");
a.add("hello2");
a.add("hello3");
a.add("hello4");
a.add("hello5");
Iterator<String> i = a.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
}
}
结果
hello1
hello2
hello3
hello4
hello5
五、简单实现
两个事业部统计各自员工数据,先为员工创建一个实体类:
public class Employee{
private String name;
private int age;
private String sex;
private String position;
public Employee(String name ,int age,String sex,String position){
this.name = name;
this.age= age;
this.sex= sex;
this.position= position;
}
@Override
public String toString (){
return "Employee{"+
"name='"+name+'\''+
",age="+age+
",sex="+sex+
",position = "+position+'\''+
'}';
}
}
为了简化代码就不提供set和get方法了,并在两个事业部中使用固定数据
public class CompanyA{
private List<Employee> list = new ArrayList<>();
public CompanyA(){
list.add(new Employee("小民",96,"男","程序员"));
list.add(new Employee("小芸",22,"女","测试"));
list.add(new Employee("小方",18,"女","测试"));
list.add(new Employee("可儿",21,"女","设计"));
list.add(new Employee("朗晴",19,"女","设计"));
}
public List<Employee> getEmployees(){
return list;
}
}
public class CompanyB{
private Employee[] array = new Employee[3];
public CompanyB(){
array[0]=new Employee("辉哥",108,"男","程序员");
array[1]=new Employee("小红",98,"男","程序员");
array[2]=new Employee("小辉",88,"男","程序员");
}
public Employee[] getEmployees(){
return array;
}
}
所以查看时要变里两个容器:
public class Boss{
public static void main(String [] args){
CompanyA a = new CompanyA();
List aList = a.getEmployees();
for(int i = 0;i<aList.size();i++){
System.out.println(aList.get(i).toString());
}
CompanyB b = new CompanyB();
Employee[] bArray = b.getEmployees();
for(int i = 0;i<bArray .length;i++){
System.out.println(bArray[i]);
}
}
}
如果还有其他部门,那么都要在Boss类中增加一段遍历逻辑,这时候用迭代器模式,将遍历封装。
定义一个迭代器接口:
public interface Iterator{
// 是否还有下一个
boolean hasNext();
//返回当前元素,并将位置移动到下一位
Object next();
}
分别对两个部门创建迭代器
public class AIterator implements Iterator{
private List<Employee> list;
private int position;
public AIterator(List<Employee> list){
this.list = list;
}
@Override
public boolean hasNext(){
return !(position>list.size-1||list.get(position)==null)
}
@Override
public Object next(){
Employee e = list.get(position);
position++;
return e;
}
}
public class BIterator implements Iterator{
private Employee[] array;
private int position;
public BIterator(Employee[] array){
this.array= array;
}
@Override
public boolean hasNext(){
return !(position>array.length-1||array[position]==null)
}
@Override
public Object next(){
Employee e = array.[position];
position++;
return e;
}
}
同时我们定义一个容器类的接口,能返回一个容器迭代器
public interface Company{
Iterator iterator();
}
这时我们修改两个部门类实现容器接口,并返回对应的迭代器对象
public class CompanyA implements Company{
private List<Employee> list = new ArrayList<>();
public CompanyA(){
list.add(new Employee("小民",96,"男","程序员"));
list.add(new Employee("小芸",22,"女","测试"));
list.add(new Employee("小方",18,"女","测试"));
list.add(new Employee("可儿",21,"女","设计"));
list.add(new Employee("朗晴",19,"女","设计"));
}
public List<Employee> getEmployees(){
return list;
}
@Override
public Iterator iterator(){
return new AIterator(list);
}
}
public class CompanyB implements Company{
private Employee[] array = new Employee[3];
public CompanyB(){
array[0]=new Employee("辉哥",108,"男","程序员");
array[1]=new Employee("小红",98,"男","程序员");
array[2]=new Employee("小辉",88,"男","程序员");
}
public Employee[] getEmployees(){
return array;
}
@Override
public Iterator iterator(){
return new BIterator(array);
}
}
最后在Boss中查阅时变得更简单
public class Boss{
public static void main(String [] args){
CompanyA a = new CompanyA();
check(a.iterator());
CompanyB b = new CompanyB();
check(b.iterator());
}
private static void check(Iterator iterator){
while(iterator.hasNext()){
System.out.println(iterator.next().toString());
}
}
}
六、模式的优缺点:
迭代器就是把容器中遍历对象的功能提取出来,这样既不暴露容器的细节,又可以让外部访问容器内部的内容。
优点
- 支持不同的方式去遍历一个容器,也可以有多个遍历,弱化了容器和遍历算法之间的关系。
- 不用用户自己去实现遍历功能,也分离了容器和遍历算法,避免了容器承担过多功能。
- 封装性更好,方便修改遍历算法而不用修改容器。
缺点 - 类文件会增加,所以对于简单的遍历来说不是很重要。
网友评论