阅读 179

迭代器模式在项目中的应用

这是我参与更文挑战的第7天,活动详情查看: 更文挑战

迭代器模式,常⻅见的就是我们⽇常使⽤的iterator遍历。虽然这个设计模式在我们的实际业务开发中的场景并不多,但却⼏乎每天都要使⽤jdk为我们提供的list集合遍历。迭代器模式的特点是实现 Iterable接⼝,通过next的⽅式获取集合元素,同时具备对元素的删除等操作。

960

我们先看一段代码:

public static void test(Collection col){
	Iterator it = col.iterator();
	while(it.hasNext()){
		String s = (String)it.next();
		System.out.println(s);
	}
}
复制代码

这个方法类似的逻辑我们经常见到,作用是循环打印一个字符串集合,里面就用到了迭代器模式,java语言已经完整地实现了迭代器模式,Iterator就是迭代器的意思。迭代器的作用就是把容器中的对象一个一个地遍历出来。

迭代器模式的角色

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

使用场景

  • 当你需要访问一个聚合对象,而且不管这些对象是什么都需要遍历的时候,就应该考虑使用迭代器模式。
  • 当需要对聚集有多种方式遍历时,可以考虑去使用迭代器模式。

优缺点

  • 遍历方式多样化,对有序列表,我们可以根据需要提供正序遍历,倒序遍历,使用者只需要得到我们实现好的迭代器即可。
  • 在一定程度上增加了系统的复杂性。

代码示例

  1. 我们先定一个抽象的迭代器
//抽象迭代器定义
public interface MyIterator<T> {
    T next();
    boolean hasNext();
}
复制代码
  1. 定义个抽象容器
public interface IcollectionCrud<T> {
    void add(T obj);
    void remove(T obj);
    MyIterator<T> iterator();

}
复制代码
  1. 具体实现上面定义的2个迭代器和容器
//具体的迭代器
public class ConcreteIterator<T> implements MyIterator<T> {
    private List<T> list ;
    private int index = 0;

    public ConcreteIterator(List list) {
        this.list = list;
    }

    @Override
    public T next() {
        T obj = null;
        if(this.hasNext()){
            obj = this.list.get(index++);
        }
        return obj;

    }

    @Override
    public boolean hasNext() {
        if(index==list.size()){
            return false;
        }
        return true;
    }
}

复制代码
//具体集合增删改成实现类
public class ConcreteCollCrud<T> implements IcollectionCrud<T>{

    private List list = new ArrayList();

    @Override
    public void add(T obj) {
        list.add(obj);
    }

    @Override
    public void remove(T obj) {
        list.remove(obj);
    }


    @Override
    public MyIterator<T> iterator() {
        return new ConcreteIterator(list);
    }
}

复制代码
  1. 我们用客户端进行调用
public class Client {
    public static void main(String[] args) {
        IcollectionCrud<String> icollectionCrud = new ConcreteCollCrud<>();
        icollectionCrud.add("1");
        icollectionCrud.add("2");
        icollectionCrud.add("3");
        icollectionCrud.add("4");
        MyIterator<String> iterator = icollectionCrud.iterator();
        while (iterator.hasNext()) {
            String str = iterator.next();
            System.out.println(str);
        }
    }
}
复制代码

结果

1 2 3 4

大家可以看到上面写的是不是跟我们平时jdk提供的集合类遍历是一模一样的。接着我们就看一下jdk是咋实现的。

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 方法就相当于我们定义的 MyIterator

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];
         }
 ​
         ...
     }
 }

复制代码

上面这个是Iterator的实现类,其实在我们常用的ArrayList中有一个内部实现类Itr ,它就实现了Iterator接口 ,其中hasNext方法和next()方法实现也非常简单,我们继续往下看在ArrayList内部还有几个迭代器对Itr进行了进一步扩展,首先看Listltr :

private class ListItr extends Itr implements ListIterator<E> {
    ListItr(int index) {
        super();
        cursor = index;
    }

    public boolean hasPrevious() {
        return cursor != 0;
    }

    public int nextIndex() {
        return cursor;
    }

    public int previousIndex() {
        return cursor - 1;
    }

}

复制代码

同样迭代器模式在MyBatis中也是必不可少的,感兴趣的大家可以自己看看源码。

文章分类
后端