设计模式之迭代器模式

1. 迭代器模式概念

迭代器模式可能是JAVA中最广为人知的模式之一,JAVA程序员在使用集合时,并不需要关注其类型是List、Set还是其他的,因为它们的遍历都可以通过迭代器来完成。迭代器模式在客户访问类和聚合类之间插入,分离了聚合对象与其遍历行为,对客户也隐藏了其内部细节,满足单一职责原则和开闭原则。

迭代器模式优点:

  • 访问一个聚合对象的内容而无须暴露它的内部表示。
  • 遍历任务交由迭代器完成,这简化了聚合类。
  • 增加新的聚合类和迭代器类都很方便,无须修改原有代码。

迭代器模式缺点:

  • 增加了类的个数,这在一定程度上增加了系统的复杂性。

迭代器模式类图如下:

设计模式之迭代器模式_第1张图片

  • 抽象聚合(Aggregate):也叫抽象容器,定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
  • 具体聚合(ConcreteAggregate):也叫具体容器,实现内部不同结构,返回一个迭代器实例。
  • 抽象迭代器(Iterator):定义访问和遍历聚合元素的接口。
  • 具体迭代器(ConcreteIterator):实现抽象迭代器接口中的方法,完成对聚合对象的遍历,记录遍历的当前位置。

2. 迭代器模式案例

通过迭代器模式实现一个简单的ArrayList,功能包括:添加元素、删除元素、获取元素、遍历元素、获取元素个数。

2.1 抽象迭代器

新建抽象迭代器接口定义迭代器行为,接口名称为Iterator,内容如下:

public interface Iterator<T> {

    /**
     * 是否有下一个元素
     */
    Boolean hasNext();

    /**
     * 返回下一个元素
     */
    T next();
}

2.2 抽象聚合

新建抽象聚合接口用来定义集合的行为,接口名称为Aggregate,内容如下:

public interface Aggregate<T> {

    /**
     * 添加元素
     * @param item 元素
     */
    void addItem(T item);

    /**
     * 删除元素
     * @param item 元素
     * @return
     */
    void remove(T item);

    /**
     * 获取元素
     */
    T getItem(Integer index);

    /**
     * 获取元素总个数
     */
    Integer size();

    /**
     * 获取迭代器
     */
    Iterator<T> iterator();

}

2.3 具体迭代器

新建具体迭代器类实现抽象迭代器,类名为ConcreteIterator,内容如下:

public class ConcreteIterator<T> implements Iterator<T> {

    /**
     * 聚合对象
     */
    private Aggregate aggregate;

    /**
     * 游动的索引指针
     */
    private Integer position;

    public ConcreteIterator(Aggregate aggregate){
        this.aggregate = aggregate;
        position = 0;
    }

    @Override
    public Boolean hasNext() {
        // 当索引指针没有游动到最后表示还有元素可以遍历
        return position < aggregate.size() ;
    }

    @Override
    public T next() {
        if (hasNext()) {
            // 返回索引指针处的元素
            return (T) aggregate.getItem(position++);
        }
        return null;
    }
}

2.4 具体聚合

新建具体聚合类实现抽象聚合,类名称为ConcreteAggregate,内容如下:

public class ConcreteAggregate<T> implements Aggregate<T> {

    /**
     * 数组容器初始大小
     */
    public static final Integer INIT_SIZE = 10;

    /**
     * 元素个数
     */
    private Integer size;

    /**
     * 实际容器
     */
    private Object[] array;

    public ConcreteAggregate(){
        array = new Object[INIT_SIZE];
        size = 0;
    }

    @Override
    public void addItem(T item) {
        if (size < array.length){
            // 容量满足
            array[size++] = item;
        } else {
            // 容量不够,需要扩容
            Object[] newArray = new Object[size + size / 2];
            System.arraycopy(array, 0, newArray, 0, size);
            newArray[size++] = item;
            array = newArray;
        }
    }

    @Override
    public void remove(T item) {
        for (int index = 0; index < array.length; index++) {
            if (array[index].equals(item)){
                Object[] newArray = new Object[size - 1];
                // 复制删除元素位置前的元素
                System.arraycopy(array, 0, newArray, 0, index);
                // 复制删除元素位置后的元素
                System.arraycopy(array, index + 1, newArray, index, size - index - 1);
                array = newArray;
                size -= 1;
                break;
            }
        }
    }

    @Override
    public T getItem(Integer index) {
        return (T) array[index];
    }

    @Override
    public Integer size() {
        return size;
    }

    @Override
    public Iterator<T> iterator() {
        return new ConcreteIterator<>(this);
    }
}

2.5 客户端

新建客户端测试容器功能和迭代功能,内容如下:

public class Client {
    public static void main(String[] args) {
        // 创建一个自定义容器
        Aggregate<String> aggregate = new ConcreteAggregate<>();

        // 给容器添加20个元素
        for (int index = 0; index < 20; index++) {
            aggregate.addItem("Hello World " + index);
        }
        System.out.println("删除前的size = " + aggregate.size());

        // 移除容器中的某个元素
        aggregate.remove("Hello World 3");
        System.out.println("删除后的size = " + aggregate.size());

        // 获取迭代器进行迭代输出
        Iterator<String> iterator = aggregate.iterator();
        int i = 0;
        while (iterator.hasNext()){
            System.out.println(String.format("item[%d] = %s", ++i, iterator.next()));
        }
    }
}

设计模式之迭代器模式_第2张图片

3. 迭代器模式应用

如今,迭代器在大多数编程语言中都很流行,它可能是JAVA中使用最广泛的集合包,当使用循环遍历集合时,它也在语言级别实现:

for (String item : list) {
    System.out.println("item = " + item);
}

在JAVA语言的ArrayList中有如下结构:

设计模式之迭代器模式_第3张图片

  • Collection是JAVA集合类的顶级接口,里面定义了获取元素个数、获取迭代器、添加元素、移除元素等方法。
  • Iterable是可迭代性的标志,该接口定义了获取迭代器的方法,迭代器的接口是Iterator,定义了hasNext和next方法。
  • ArrayList是具体的聚合类,继承了AbstractList抽象类,在这个抽象类中使用内部类Itr来实现迭代器接口充当具体迭代器。

你可能感兴趣的:(JAVA笔记,JAVA设计模式,JAVA,设计模式,迭代器模式)