zoukankan      html  css  js  c++  java
  • 结合JDK源码看设计模式——迭代器模式

    前言:

      Iterator翻译过来就是迭代器的意思。在前面的工厂模式中就介绍过了iterator,不过当时介绍的是方法,现在从Iterator接口的设计来看,似乎又是一种设计模式,下面我们就来讲讲迭代器模式到底是怎么实现的。

    一、定义

      提供一种方法,顺序访问一个集合对象中的各个元素,而又不暴露该对象的内部表示。(可以理解为遍历)

    二、适用场景

    1、访问一个集合对象的内容而无需暴露它的内部表示

    2、为遍历不同的集合结构提供一个统一的接口

      重要的是对第二点的理解,前面我们在工厂方法中讲过iterator是个工厂方法,Iterator是个产品总接口。对于我们需要的是Iterator这个产品,产品的功能是遍历,我们并不关心这个产品里面存储的结构是List还是Map,不同存储结构的遍历实现应该交给下面的不同的工厂去实现。这里同样也可以这么理解。但是,我们今天讲的是迭代器模式。工厂模式是创建型,而这个模式是行为型。在这里我们或许可以先抛开工厂模式,来去理解这个迭代器模式。

    三、结合Iterator接口看迭代器

    迭代器模式的角色构成

     1、迭代器(Iterator):定义访问和遍历元素的接口。

     2、具体迭代器(ConcreteIterator ):具体迭代器,实现了迭代器接口,内部会具体实现如何遍历当前聚合。

     3、聚合(Aggregate):内部创建相应迭代器接口的方法。

     4、具体聚合(ConcreteAggregate):内部具体有存储方式以及实现相应迭代器接口,以及一些操作。

      下面我们来结合源码来理解上面4个角色具体是什么样的:

    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());
        }
    }

      上面是迭代器Iterator接口的代码,定义了一些需要子类实现的方法和默认的方法。在这里说一下上面两个default方法都是JDK1.8之后才有的接口新特性,在JDK1.8之前接口中不能有方法实体。

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        private class Itr implements Iterator<E> {
            int cursor;       // index of next element to return
            int lastRet = -1; // index of last element returned; -1 if no such
            int expectedModCount = modCount;
    
            public boolean hasNext() {
                return cursor != size;
            }
    
            @SuppressWarnings("unchecked")
            public E next() {
                checkForComodification();
                int i = cursor;
                if (i >= size)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];
            }
    
            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();
    
                try {
                    ArrayList.this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
    
            @Override
            @SuppressWarnings("unchecked")
            public void forEachRemaining(Consumer<? super E> consumer) {
                Objects.requireNonNull(consumer);
                final int size = ArrayList.this.size;
                int i = cursor;
                if (i >= size) {
                    return;
                }
                final Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length) {
                    throw new ConcurrentModificationException();
                }
                while (i != size && modCount == expectedModCount) {
                    consumer.accept((E) elementData[i++]);
                }
                // update once at end of iteration to reduce heap write traffic
                cursor = i;
                lastRet = i - 1;
                checkForComodification();
            }
    
            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }
    }

      上面是简化的ArrayList类,因为具体实现迭代器Itr的类在ArrayList中作为内部类存在,这个内部类将接口中的方法做了具体实现,并且是只对ArrayList这个类进行实现的。

    public interface List<E> extends Collection<E> {
        Iterator<E> iterator();
    }

      上面是简化的List接口,充当的是聚合接口,可以看见内部创建了相应迭代器接口的方法。

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        public Iterator<E> iterator() {
            return new Itr();
        }
    }

      上面是简化的ArrayList类,充当的是具体聚合类角色,在这里是直接返回了一个具体实现迭代器的类。

    public class Test1 {
    
        public static void main(String[] args) {
          List<Integer> a=new ArrayList<>();
          a.add(1);
          a.add(2);
          a.add(3);
          while(a.iterator().hasNext()){
              System.out.println(a.iterator().next());
          }
        }
    }

      这是一个错误的测试类,因为我们每调用一次iterator方法都是会new一个Itr对象,也就是里面的游标会一直重置为0,所以会无限循环。下面才是正确的测试方法

    public class Test1 {
    
        public static void main(String[] args) {
          List<Integer> a=new ArrayList<>();
          a.add(1);
          a.add(2);
          a.add(3);
          Iterator Itr=a.iterator();
          while(Itr.hasNext()){
              System.out.println(Itr.next());
          }
        }
    }

    四、总结

      平常写代码的时候总会有使用iterator。但是如果要我们自己去动手实现一个集合类的会很少,除非是写框架的时候,大多数我们还是使用为主。当我们需要使用迭代器模式的时候,只需要看上面4个源码的角色扮演和分析,很快就能写出自己的迭代器。前面在适用场景的时候我们是用工厂方法模式来去理解Iterator,但学完这个模式之后,以后的Iterator接口下的实现类,你都可以认为是迭代器模式。因为迭代器模式在各种集合对象中用的实在是太广泛了,所以专门拿这个模式进行源码解释。

  • 相关阅读:
    机器学习第二次作业
    机器学习上机作业
    机器学习第一次作业
    软工实践个人总结
    第08组 Beta版本演示
    第08组 Beta冲刺(5/5)
    第08组 Beta冲刺(4/5)
    第08组 Beta冲刺(3/5)
    第08组 Beta冲刺(2/5)
    第08组 Beta冲刺(1/5)
  • 原文地址:https://www.cnblogs.com/Cubemen/p/10688624.html
Copyright © 2011-2022 走看看