likes
comments
collection
share

「设计模式」迭代器模式

作者站长头像
站长
· 阅读数 52

一、概述

迭代器模式(Iterator Pattern)提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。这种类型的设计模式属于行为型模式。

JDK中的集合类型,例如:List,Set,Map,他们的具体子类几乎都实现了迭代器模式。这样的好处就是,我们可以使用迭代器模式直接遍历内部对象,而不比考虑这个集合的类型是List还是Set还是Map。

迭代器模式的4种角色

(1)抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。

(2)具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。

(3)抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。

(4)具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

二、优缺点

优点:

  • 支持不同方式遍历一个聚合对象,在同一个聚合上可以有多个遍历。
  • 简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再自行提供数据遍历等方法。
  • 在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码。

缺点:

  • 在某些情况下,可能比直接遍历效率低。
  • 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

三、实现方式

迭代器模式不再自己举例实现了,因为在JDK中java.util.Iterator就是最完美的实例,下面以ArrayList源码为例。

遍历List的几种方式

public class Client {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("s1");
        list.add("s2");
        list.add("s3");

        /**
         *  第一种遍历方式:for循环
         */
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        /**
         *   第二种遍历方式:foreach循环
         *   底层是基于迭代器来实现的
         */
        for (String name : list) {
            System.out.println(name);
        }

        /**
         *   第三种遍历方式:迭代器遍历
         */
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

    }
}

抽象迭代器(Iterator)

public interface Iterator<E> {

    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

具体迭代器实现(Itr)

private class Itr implements Iterator<E> {
        int cursor;
        int lastRet;
        int expectedModCount;

        private Itr() {
            this.lastRet = -1;
            this.expectedModCount = ArrayList.this.modCount;
        }

        public boolean hasNext() {
            return this.cursor != ArrayList.this.size;
        }

        public E next() {
            this.checkForComodification();
            int var1 = this.cursor;
            if (var1 >= ArrayList.this.size) {
                throw new NoSuchElementException();
            } else {
                Object[] var2 = ArrayList.this.elementData;
                if (var1 >= var2.length) {
                    throw new ConcurrentModificationException();
                } else {
                    this.cursor = var1 + 1;
                    return var2[this.lastRet = var1];
                }
            }
        }

        public void remove() {
            if (this.lastRet < 0) {
                throw new IllegalStateException();
            } else {
                this.checkForComodification();

                try {
                    ArrayList.this.remove(this.lastRet);
                    this.cursor = this.lastRet;
                    this.lastRet = -1;
                    this.expectedModCount = ArrayList.this.modCount;
                } catch (IndexOutOfBoundsException var2) {
                    throw new ConcurrentModificationException();
                }
            }
        }

        public void forEachRemaining(Consumer<? super E> var1) {
            Objects.requireNonNull(var1);
            int var2 = ArrayList.this.size;
            int var3 = this.cursor;
            if (var3 < var2) {
                Object[] var4 = ArrayList.this.elementData;
                if (var3 >= var4.length) {
                    throw new ConcurrentModificationException();
                } else {
                    while(var3 != var2 && ArrayList.this.modCount == this.expectedModCount) {
                        var1.accept(var4[var3++]);
                    }

                    this.cursor = var3;
                    this.lastRet = var3 - 1;
                    this.checkForComodification();
                }
            }
        }

        final void checkForComodification() {
            if (ArrayList.this.modCount != this.expectedModCount) {
                throw new ConcurrentModificationException();
            }
        }
    }

抽象聚合器(List)

public interface List<E> extends Collection<E> {

    Iterator<E> iterator();

}

具体聚合类实现(ArrayList)

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
  

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

四、常见应用场景

  1. 访问一个聚合对象的内容而无须暴露它的内部表示。
  2. 需要为聚合对象提供多种遍历方式。
  3. 为遍历不同的聚合结构提供一个统一的接口。
转载自:https://juejin.cn/post/7145450262079995941
评论
请登录