一文带你理解迭代器模式

作为一个使用Java语言的开发者,对于迭代器应该不陌生,在对集合进行遍历时,几乎都能遇到。迭代器作为访问者和容器类之间的第三者,它提供了一种对集合元素进行顺序访问的统一实现方式。

定义

提供一种方法顺序的访问一个容器中的各个元素,而又不需要暴露对象的内部表示。

场景

遍历一个容器对象时。

角色

迭代器接口

定义、访问和遍历元素的接口

具体迭代器

迭代器的具体实现,记录当前游标位置

容器接口

提供创建具体迭代器角色的接口

具体容器类

具体迭代器与具体容器类进行关联

源码演示

因为迭代器一般由平台在内部进行了实现,比如说ListSet等。因此,本章节,就以Java的原生数据结构来分析。
我们来看下HashSet的迭代器实现。

首先是容器接口类Set

public interface Set<E> extends Collection<E> {

  int size();
  
  // 创建迭代器的接口
  Iterator<E> iterator();
  
  boolean add(E e);

  boolean remove(Object o);
  
}

看下实现类HashSet对于获取迭代器的实现


     private transient HashMap<E,Object> map;
     
     ...省略部分代码
     
    /**
     * Returns an iterator over the elements in this set.  The elements
     * are returned in no particular order.
     *
     * @return an Iterator over the elements in this set
     * @see ConcurrentModificationException
     */
    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }

可以看到最终是调用了HashMapkeySetiterator方法。

    public Set<K> keySet() {
        Set<K> ks = keySet;
        if (ks == null) {
            ks = new KeySet();
            keySet = ks;
        }
        return ks;
    }

从上述代码可以看出keySe是一个KeySet类型,接下来看下KeySet的``iterator```方法。

public final Iterator<K> iterator() {
    return new KeyIterator();
  }

实际上就是返回了一个KeyIterator对象。

final class KeyIterator extends HashIterator
    implements Iterator<K> {
  public final K next() {
    return nextNode().key;
  }
}

这里可以看出最终的逻辑还是在HashIterator类里面

import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.NoSuchElementException;

abstract class HashIterator {
  HashMap.Node<K,V> next;        // next entry to return
  HashMap.Node<K,V> current;     // current entry
  int expectedModCount;  // for fast-fail
  int index;             // current slot

  HashIterator() {
    expectedModCount = modCount;
    HashMap.Node<K,V>[] t = table;
    current = next = null;
    index = 0;
    if (t != null && size > 0) { // advance to first entry
      do {} while (index < t.length && (next = t[index++]) == null);
    }
  }

  public final boolean hasNext() {
    return next != null;
  }

  final HashMap.Node<K,V> nextNode() {
    HashMap.Node<K,V>[] t;
    HashMap.Node<K,V> e = next;
    if (modCount != expectedModCount)
      throw new ConcurrentModificationException();
    if (e == null)
      throw new NoSuchElementException();
    if ((next = (current = e).next) == null && (t = table) != null) {
      do {} while (index < t.length && (next = t[index++]) == null);
    }
    return e;
  }

  public final void remove() {
    HashMap.Node<K,V> p = current;
    if (p == null)
      throw new IllegalStateException();
    if (modCount != expectedModCount)
      throw new ConcurrentModificationException();
    current = null;
    K key = p.key;
    removeNode(hash(key), key, null, false, false);
    expectedModCount = modCount;
  }
}

重点看下nextNode方法,在这里返回了下一个节点的对象,并将next指针向后移到动一位,从而实现遍历操作。代码看起来比较复杂,但是整体逻辑清晰,而且使用起来极为方便。

总结

迭代器模式的优点很明显也很单一,就是对容器元素提供遍历操作。它支持以不同的方式去遍历,也支持多个遍历同时进行,同时也弱化了容器了和遍历算法之间的关系。缺点也是设计模式的共同缺点,会增加类文件数量。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值