当前位置: 移动技术网 > IT编程>软件设计>设计模式 > 结合JDK源码看设计模式——迭代器模式

结合JDK源码看设计模式——迭代器模式

2019年04月12日  | 移动技术网IT编程  | 我要评论

前言:

  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接口下的实现类,你都可以认为是迭代器模式。因为迭代器模式在各种集合对象中用的实在是太广泛了,所以专门拿这个模式进行源码解释。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网