迭代器模式---Iterator

Posted 高高for 循环

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迭代器模式---Iterator相关的知识,希望对你有一定的参考价值。

迭代器模式

定义:

迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF 给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。

  • 迭代器模式可以为不同容器提供一致的遍历行为,而且不用关心内部元素的组成结构,属于行为型模式。
  • 迭代器模式的本质就是抽离集合对象迭代行为到迭代容器中,并提供统一的访问接口
  • 迭代器模式是针对集合对象而生的,对于集合对象而言,肯定会涉及到对集合的添加和删除操作,同时也肯定支持遍历集合元素的操作,我们此时可以把遍历操作放在集合对象中,但这样的话,集合对象既承担太多的责任了,面向对象设计原则中有一条就是单一职责原则,所有我们要尽可能地分离这些职责,用不同的类取承担不同的责任,迭代器模式就是用迭代器类来承担遍历集合的职责。

结构:

在这里插入图片描述
在这里插入图片描述

案例

自定义容器,分别为数组实现 和单向链表实现

Collection02 集合接口

public interface Collection02<E> {
    void add(E o);
    int size();

    Iterator02 iterator();

}

Iterator02 迭代器接口

public interface Iterator02<E> { //Element //Type //K //Value V Tank
    boolean hasNext();

    E next();

}

ArrayList02

内部数据结构为数组

package Iterator;

public class ArrayList02<E> implements Collection02<E> {

    E[] objects = (E[])new Object[10];
    //objects中下一个空的位置在哪儿,或者说,目前容器中有多少个元素
    private int index = 0;

    public void add(E o) {
        if(index == objects.length) {
            E[] newObjects = (E[])new Object[objects.length*2];
            System.arraycopy(objects, 0, newObjects, 0, objects.length);
            objects = newObjects;
        }

        objects[index] = o;
        index ++;
    }

    public int size() {
        return index;
    }

    @Override
    public Iterator02<E> iterator() {
        return new ArrayListIterator();
    }

    private class ArrayListIterator<E> implements Iterator02<E> {

        private int currentIndex = 0;

        @Override
        public boolean hasNext() {
            if(currentIndex >= index) return false;
            return true;
        }

        @Override
        public E next() {
            E o = (E)objects[currentIndex];
            currentIndex ++;
            return o;
        }
    }


}

测试类 Main

public class Main {
    public static void main(String[] args) {
        Collection02 list = new ArrayList02();
        for(int i=0; i<15; i++) {
            list.add(new String("s" + i));
        }
        System.out.println("集合size= "+list.size());

        //这个接口的调用方式:
        Iterator02 it = list.iterator();
        while(it.hasNext()) {
            Object o = it.next();
            System.out.println(o);
        }
    }

}

在这里插入图片描述

LinkedList02

内部数据结构为 单向链表

public class LinkedList02<E> implements Collection02<E> {
    Node head = null;
    Node tail = null;
    //目前容器中有多少个元素
    private int size = 0;


    @Override
    public void add(E o) {
        Node n = new Node(o);
        n.next = null;

        if(head == null) {
            head = n;
            tail = n;
        }

        tail.next = n;
        tail = n;
        size++;

    }

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

    @Override
    public Iterator02 iterator() {
        return  new LinkedListIterator();
    }


    private class Node {
        private E o;
        Node next;

        public Node(E o) {
            this.o = o;
        }
    }


    private  class LinkedListIterator<E> implements Iterator02<E>{

        private  int  currentIndex=1;
        Node node;

        @Override
        public boolean hasNext() {
            if(currentIndex <=size){
                return true;
            }
            return false;
        }

        @Override
        public E next() {
            if(currentIndex==1){
                node=head;
            }else {
                node=node.next;
            }
            currentIndex++;
            return (E) node.o;
        }
    }

}

测试类 Main

public class Main {
    public static void main(String[] args) {
        Collection02 list = new LinkedList02();
       
        for(int i=0; i<15; i++) {
            list.add(new String("s" + i));
        }
        System.out.println("集合size= "+list.size());

        //这个接口的调用方式:
        Iterator02 it = list.iterator();
        while(it.hasNext()) {
            Object o = it.next();
            System.out.println(o);
        }
    }

}

在这里插入图片描述

源码应用

JDK源码中应用 ArrayList

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        for(int i=0; i<15; i++) {
            list.add(new String("s" + i));
        }
        System.out.println("集合size= "+list.size());

        //这个接口的调用方式:
        Iterator<String> it = list.iterator();
        while(it.hasNext()) {
            Object o = it.next();
            System.out.println(o);
        }
    }

}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

MyBatis源码中迭代器模式体现

MyBatis的源码包cursor就是迭代器模式的应用,下面是缓存包的包结构:
在这里插入图片描述
从上面的包结构图结合具体的代码可知内容如下:

下面来看 DefaultCursor 类,源码如下。

public class DefaultCursor<T> implements Cursor<T> {
    ...
    private final CursorIterator cursorIterator = new CursorIterator();
    ...
}

DefaultCursor 实现了 Cursor 接口,且定义了一个成员变量 cursorIterator,其类型为 CursorIterator。

继续查看 CursorIterator 类的源码实现,它是 DefaultCursor 的一个内部类,实现了 JDK 中的 Iterator 接口,源码如下。

private class CursorIterator implements Iterator<T> {
    T object;
    int iteratorIndex;
 
    private CursorIterator() {
        this.iteratorIndex = -1;
    }
 
    public boolean hasNext() {
        if (this.object == null) {
            this.object = DefaultCursor.this.fetchNextUsingRowBound();
        }
 
        return this.object != null;
    }
 
    public T next() {
        T next = this.object;
        if (next == null) {
            next = DefaultCursor.this.fetchNextUsingRowBound();
        }
 
        if (next != null) {
            this.object = null;
            ++this.iteratorIndex;
            return next;
        } else {
            throw new NoSuchElementException();
        }
    }
 
    public void remove() {
        throw new UnsupportedOperationException("Cannot remove element from Cursor");
    }
}

总结:

使用场景:

  1. 访问一个聚合对象的内容而无须暴露它的内部表示。
  2. 需要为聚合对象提供多种遍历方式。
  3. 为遍历不同的聚合结构提供一个统一的接口。

优点:

  1. 解耦了迭代与集合
    迭代器模式封装具体的迭代算法,即使迭代器内部算法发生变化,也不会影响到原有的集合对象。

  2. 简化了集合对象接口
    迭代器模式将集合对象本身应该提供的元素迭代接口放到了迭代器中,使得集合对象可以无需关心具体的迭代行为。

  3. 多态迭代
    迭代器模式为不同聚合结构的集合提供了一致的遍历接口,即一个迭代器可以用来迭代不同的集合对象。

  4. 元素迭代功能的多样化
    每个集合可以提供一个或者多个不同功能的迭代器,使得同种元素可以有不同的迭代行为。

缺点:

  • 迭代器模式如果用于简单的数据结构(如数组或者链表)时,反而会使得迭代元素方式变得更加繁琐复杂化

另:

  • 迭代器模式常常与组合模式结合起来使用,在对组合模式中的容器构件进行访问时,经常将迭代器潜藏在组合模式的容器构成类中。当然,也可以构造一个外部迭代器来对容器构件进行访问,其结构图如图
    在这里插入图片描述

以上是关于迭代器模式---Iterator的主要内容,如果未能解决你的问题,请参考以下文章

GOF23设计模式之迭代器模式(iterator)

迭代器模式(Iterator Pattern)

设计模式之迭代器模式 Iterator

设计模式——迭代器(Iterator)模式

Iterator(迭代器)

迭代器模式 (Iterator)