• Java设计模式-迭代器模式


    迭代器模式是一种应用很广泛的设计模式,提供了一种方法顺序的访问一个集合中的元素,但是还不暴露该对象的内部细节。

    提供了一种方法遍历访问整个聚合的对象,这个聚合的对象一般是一个集合。把元素间的移动交给迭代器,不需要聚合对象的操作,就可以实现整个聚合对象的遍历。

    源码分析:

    在java中就有迭代器模式的实现,对于java集合的遍历,List,Set,Map就要用到迭代器模式。

    public class IteratorTest {
        public static void main(String[] args) {
            List list = new ArrayList();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            Iterator it = list.iterator();
            while (it.hasNext()) {
                int element = (int) it.next();
                System.out.println(element);
            }
        }
    }
    

    上面对List集合的遍历就用到迭代器模式,我们不用知道元素内部的细节实现,只是简单的调用,就可以实现对集合的遍历,下面看看迭代器在源码上是怎么的实现的。

    如果想要使用迭代器,就要用到Iterator接口,Iterator接口很简单只有三个未实现的抽象方法:


    接下来我们看集合类对这些方法的实现,List接口声明了iterator方法


    ArrayList类具体实现了iterator方法:

    public Iterator<E> iterator() {
        return new Itr();
    }
    
    /**
     * An optimized version of AbstractList.Itr
     */
    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();
            }
        }
    
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

    ArrayList类中通过一个内部类实现Iterator中的方法。具体的实现还是很简单的。

    //————————————————————————————————————————————————————————//

    修改于2017/10/2

    看完了迭代器模式,也看了源码的实现原理,但是忘记了一个最重要最容易出错的方法remove(),这是一个移除集合中的元素的方法,看着很简单,最容易忽略,这个方法的使用尤其要注意他是与next()方法联用的,至于为什么,先看测试代码:创建集合添加元素,调用next()方法,之后调用remove(),可以正常的移除第一个元素,第二次调用remove()方法,运行报错。在remove()方法的实现上是依赖于next()方法中的一个赋值语句,看源码


    List list = new ArrayList();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    Iterator it = list.iterator();
    it.next();
    it.remove();
    
    //it.remove();//运行报错
     for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i));}

    在remove()方法中有一个变量lastRet,在方法的最开始就会判断这个变量的值是否小于0,而这个值在初始化的时候就初始化为-1,当直接调用remove()方法的时候,就会检查lastRet的值,一定会报错。这个值只有在next()方法中才更改了值,每次调用next()方法,这个变量laseRet的值都会等于遍历的当前元素,如果在这时候操作集合,直接调用集合的remove()方法,在next()方法的开始就会报错。



    //————————————————————————————————————————————————————————//

    根据源码我们可以看到迭代器模式的实现和结构,自己动手实现迭代器模式。

    迭代器模式的结构:

    • 抽象容器:一般是一个接口,提供一个iterator()方法。
    • 具体容器:就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet,TreeSet等。
    • 抽象迭代器:定义遍历元素所需要的方法,一般来说会有这么三个方法:取得第一个元素的方法first(),取得下一个元素的方法next(),判断是否遍历结束的方法isDone()(或者叫hasNext()),移出当前对象的方法remove(),
    • 迭代器实现:实现迭代器接口中定义的方法,完成集合的迭代。
    利用这个结构我们进行模拟

    代码模拟:

    首先一个迭代器接口,里面有迭代抽象方法,和jdk提供的少写一个方法

    package demo_iterator;
    
    public interface IteratorInterface {
    
        public Object next();
    
        public boolean hasNext();
    }
    

    一个抽象的集合,定义为一个接口:有集合常用的方法,和提供一个迭代方法

    package demo_iterator;
    
    public interface ListInterface {
    
        public void add(Object object);
    
        public void remove(Object object);
    
        public IteratorInterface iterator();
    }
    

    具体实现迭代器中的方法和上面源码中的内部类功能一样,用一个ArrayList辅助实现

    package demo_iterator;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class ListClass implements IteratorInterface {
    
        private List list = new ArrayList();
        private int index = 0;
    
        public ListClass(List list) {
            this.list = list;
        }
    
        @Override
        public Object next() {
            Object object = null;
            if (this.hasNext()) {
                object = list.get(index++);
            }
            return object;
        }
    
        @Override
        public boolean hasNext() {
            if (list.size() == index) {
                return false;
            }
            return true;
        }
    
    }
    

    定义一个集合,实现抽象集合接口,也定义一个ArrayList辅助,

    package demo_iterator;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Array implements ListInterface {
        private List list = new ArrayList();
    
        @Override
        public void add(Object object) {
            list.add(object);
        }
    
        @Override
        public void remove(Object object) {
            list.remove(object);
        }
    
        @Override
        public IteratorInterface iterator() {
            return new ListClass(list);
        }
    }
    

    测试类

    package demo_iterator;
    
    public class Test {
        public static void main(String[] args) {
            
            ListInterface list = new Array();
            list.add(1);
            list.add(2);
            list.add(4);
            list.add(0);
            IteratorInterface it = list.iterator();
            while (it.hasNext()) {
                int element = (int) it.next();
                System.out.println(element);
            }
        }
    }
    

    输出:

    1
    2
    4
    0


    迭代器模式的优点:

    • 简化了遍历方式,对于对象集合的遍历,还是比较麻烦的,对于数组或者有序列表,我们尚可以通过游标来取得,但用户需要在对集合了解很清楚的前提下,自行遍历对象,但是对于hash表来说,用户遍历起来就比较麻烦了。而引入了迭代器方法后,用户用起来就简单的多了。
    • 可以提供多种遍历方式,比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了。
    • 封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心。

      迭代器模式的缺点:

    • 对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,大家可能都有感觉,像ArrayList,我们宁可愿意使用for循环和get方法来遍历集合。


    参考:http://blog.csdn.net/zhengzhb/article/details/7610745


  • 相关阅读:
    MongoDB 创建数据库
    生成树状结构
    苹果微信内置浏览器cookie
    AutoMapper
    MongoDB单表导出与导入
    CultureInfo中重要的InvariantCulture
    utf-8编码引起js输出中文乱码的解决办法
    自建的用户登录执行数据库邮件出现错误
    [转译]5种方法提高你网站的登录体验
    化繁为简——网易云音乐WP1.0设计思考
  • 原文地址:https://www.cnblogs.com/duzhentong/p/7816558.html
Copyright © 2020-2023  润新知