迭代器模式-遍历容器的统一方式

290 阅读3分钟

这是我参与8月更文挑战的第26天,活动详情查看:8月更文挑战


1. 遍历容器的统一方式

集合容器算是程序员使用最频繁的工具类之一了,其中列表的话最常用的当属ArrayList和LinkedList吧,算是两种典型的实现,分别是用了数组和链表的结构。容器的功能无非就是两类:存和取,针对不同的底层数据结构实现的容器,开发者需要如何对容器进行遍历呢?如果遍历容器需要开发者对底层数据结构非常清楚的话,会增加开发者的使用门槛。因此,统一容器的遍历方式至关重要。

由于JDK提供的List源码过于复杂,篇幅原因这里就不贴了,而是自己手写实现一个简单的容器,旨在体会迭代器的思想。 假设现在有两种容器:Array和Linked,底层分别是基于数组和链表的数据结构实现的,客户端需要对其进行遍历,类图设计如下: 在这里插入图片描述

Array基于数组实现,变量size记录了元素的数量。Linked基于链表实现,元素被封装成Node节点被加入到链尾,属性head记录的是链表的头节点,根据next可找到关联的下一个节点。

面对两种底层采用不同数据结构实现的集合容器,客户端需要这样遍历:

void traverse(Object o) {
    if (o instanceof Array) {
        Array array = (Array) o;
        for (int i = 0; i < array.size(); i++) {
            array.get(i);
        }
    }else {
        Linked linked = (Linked) o;
        Linked.Node node = linked.getHead();
        while (node != null) {
            node.getData();
            node = node.getNext();
        }
    }
}

可以看到客户端遍历非常的麻烦,需要根据不同的数据结构使用不同的方式进行遍历,如果再新增一种数据结构实现,客户端的遍历方法就要修改,违反了「开闭原则」,有没有一种统一的遍历方式呢?

当然有,类的结构优化如下: 在这里插入图片描述

编写Iterator接口,定义迭代器的功能:

interface Iterator<E> {

    // 还有下一个元素吗
    boolean hasNext();

    // 下一个元素
    E next();
}

Array实现Iterator

class ArrayIterator<E>{
    int index;
    boolean hasNext() {
        return index < size;
    }

    E next() {
        return (E) table[index++];
    }
}

Linked实现Iterator

class LinkedIterator<E>{
    Node current = head;

    boolean hasNext() {
        return current != null;
    }

    E next() {
        Node node = this.current;
        this.current = node.next;
        return (E) node.data;
    }
}

客户端可以用同样的方式进行遍历:

void traverse(Iterator iterator) {
    while (iterator.hasNext()) {
        iterator.next();
    }
}

可以看到,客户端的遍历变得非常的简单,根本就不关心容器的底层数据结构,只关心迭代器,只要你还有下一个元素我就继续取。 这就是迭代器模式!

2. 迭代器模式的定义

提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。

在这里插入图片描述

迭代器模式通用类图
  • Aggregate:抽象容器,定义容器的功能,可以创建迭代器对象。
  • ConcreteAggregate:具体的容器,底层算法实现。
  • Iterator:抽象迭代器,定义迭代器具有的功能。
  • ConcreteIterator:具体的迭代器,遍历容器的算法实现。

迭代器模式太普通了,太常用了,以至于JDK从1.2开始自带java.util.Iterator类,开发者一般来说没有理由再去自己手写迭代器模式,直接拿来主义即可。

3. 迭代器模式的优点

迭代器模式的优点和它的定义一样清晰明了,就是为不同算法实现的容器提供一个统一的遍历方式,使得客户端无需关心容器底层的数据结构,就可以轻松遍历访问元素。

4. 总结

「迭代器模式」太简单了,也太普通了,它已经融入到开发者的日常代码了,如果你是一名Java开发者,那么请放弃自己实现迭代器模式的念头吧,直接使用JDK提供的java.util.Iterator类,准没有错!