美文网首页
设计模式[16]-迭代器模式-Iterator Pattern

设计模式[16]-迭代器模式-Iterator Pattern

作者: 郭寻抚 | 来源:发表于2017-04-17 16:12 被阅读39次

    1.迭代器模式简介

    所有的java程序员对Iterator都不陌生,只要是Collection,就都可以通过iterator()方法来获取迭代器Iterator,从而访问集合中的元素。迭代器模式(Iterator Pattern)是行为型(Behavioral)设计模式,为集合类提供了遍历集合元素的行为。

    迭代器模式一共有四种角色:

    (1) Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法。

    (2) ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成对集合对象的遍历。

    (3) Aggregate(抽象聚合类):它用于存储和管理元素对象,声明了获取Iterator的抽象方法

    (4) ConcreteAggregate(具体聚合类): 实现了抽象聚合类中声明的获取Iterator的方法,返回具体迭代器。

    2. 迭代器模式举例

    下面我们模拟JDK源码中的一些类,来分析演示迭代器模式。

    序号 类名 角色 说明
    1 MyIterator Iterator 抽象迭代器
    2 Itr ConcreteIterator 具体迭代器,是MyArrayList的私有内部类
    3 MyCollection Aggregate 抽象聚合类,是集合类的接口。
    4 MyArrayList ConcreteAggregate 具体聚合类,是一种有序的、可重复的元素集合
    5 IteratorMain 客户端 演示调用
    迭代器模式

    1. MyIterator

    我们首先来看MyIterator,它一般包括3个方法,分别是判断是否还有更多的元素、得到下一个元素、删除最后一个被遍历的元素。

    public interface MyIterator<E> {
    
        // 是否还有更多的元素。
        boolean hasNext();
        
        // 得到下一个元素。
        E next();
        
        // 删除最后一个被遍历的元素,必须要在next()执行后才可以执行。
        void remove();
    
    }
    

    2. MyCollection

    MyCollection接口中定义了获取迭代器的方法,另外,我们只选取了add和remove方法,用来解释迭代器设计模式足够了。

    public interface MyCollection<E> {
        
        // 增加元素
        boolean add(E e);
    
        // 删除元素
        boolean remove(Object o);
    
        // 获取迭代器
        Iterator<E> iterator();
    }
    

    3. ArrayList 和 它的迭代器 Itr

    public class MyArrayList<E> implements MyCollection {
    
        // 存储ArrayList 中的元素
        transient Object[] elementData;
    
        /**
         * 当前集合中元素的数目
         */
        private int size;
    
        /**
         * 为了演示方便,设置定长的数组
         */
        public MyArrayList() {
            this.elementData = new Object[1024];
        }
    
        /**
         * 把指定的对象添加到集合中。仅仅是演示,不考虑数组越界的情况。
         *
         * @param o 指定的对象
         * @return true,如果添加成功的话
         */
        @Override
        public boolean add(Object o) {
            elementData[size++] = o;
            return true;
        }
    
        /**
         * 如果对象在ArrayList中存在,就移除它。
         *
         * @param o 指定移除的对象
         * @return true,如果集合中包含指定的对象
         */
        @Override
        public boolean remove(Object o) {
            if (o == null) {
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
        }
    
    
        private void fastRemove(int index) {
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index + 1, elementData, index,
                        numMoved);
            elementData[--size] = null; // clear to let GC do its work
        }
    
        /**
         * 获取集合的迭代器
         *
         * @return MyIterator
         */
        @Override
        public MyIterator iterator() {
            return new Itr();
        }
    
        // ***** 内部类,迭代器 ***** //
        private class Itr implements MyIterator<E> {
    
            // 下一个元素的游标。
            int cursor;
            // 上一个返回的元素的index,-1代表没有这样的index。
            int lastRet = -1;
    
    
            /**
             * 判断集合 是否还有更多的元素
             *
             * @return true:有;false: 没有
             */
            @Override
            public boolean hasNext() {
                return cursor != size;
            }
    
            /**
             * 获取集合中的下一个元素
             *
             * @return E 下一个元素
             */
            @Override
            public E next() {
                int i = cursor;
                if (i >= size)
                    throw new NoSuchElementException();
                Object[] elementData = MyArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];
            }
    
            /**
             * 移除上一个被访问的元素
             */
            @Override
            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                try {
                    MyArrayList.this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
        }
    }
    

    **4. 演示类 **

    public class IteratorMain {
    
        public static void main(String[] args) {
    
            System.out.println("初始化MyArrayList");
            MyArrayList<Integer> arrayList = new MyArrayList<>();
            for (int i = 0; i < 10; i++) {
                arrayList.add(i);
            }
            System.out.println("移除一条数据");
            MyIterator<Integer> iterator = arrayList.iterator();
            if(iterator.hasNext()){
                Integer i = iterator.next();
                System.out.println(i);
                iterator.remove();
            }
            System.out.println("遍历集合中的数据");
            while (iterator.hasNext()){
                Integer i = iterator.next();
                System.out.println(i);
            }
        }
    }
    

    3. 总结

    迭代器模式简化了集合的遍历方式,迭代器通常也是和集合类共生出现的;Java的中集合类中都提供了迭代器,实际的应用中使用到迭代器模式并不是很多。

    4. 拓展

    访问集合中的元素,有两种方法,一种是顺序访问,一种是随机访问;不同的集合类,可能使用不同的访问方式。以java.util.ArrayList为例,它可以通过public Iterator<E> iterator()方法获得迭代器,从而调用Iterator.next来顺序访问集合元素;同时,它还实现了java.util.RandomAccess接口,可以通过public E get(int index)方法来随机访问集合元素。

    对于实现了随机访问的集合类,即实现了RandomAccess接口的类,比如ArrayList,使用fori循环,要比Iterator快。

    // 对于实现RandomAccess的类,这样循环效率更高。
    for (int i = 0; i < list.size(); i++)
        list.get(i);
    
    // 对于实现RandomAccess的类,Iterator循环效率不如上面。
    for (Iterator i=list.iterator(); i.hasNext(); )
        i.next();   
    

    对于没有实现随机访问的集合类,例如LinkedList,fori循环速度要比for iterator要慢。
    (完)

    相关文章

      网友评论

          本文标题:设计模式[16]-迭代器模式-Iterator Pattern

          本文链接:https://www.haomeiwen.com/subject/nybtzttx.html