设计模式——迭代器模式
2016-04-26 10:49
399 查看
上次我们讲了下观察者模式《设计模式——观察者模式》,这次我们来看下迭代器模式。迭代器模式我们自己可能很少直接的使用,但是我们却经常在间接地使用,Java集合类就用到了这个模式,这个可以通过他们的源码来验证。
我们知道对容器对象的访问必然会涉及到遍历操作,一般情况下,我们的做法是将遍历的方法封装在容器中,但是这样会带来新的问题:容器类不仅要维护自身内部的数据元素,还要对外提供遍历的接口方法,这样不但显得类很臃肿,同时也违背了抽象编程原则。为了解决上面的缺点,我们可以采用迭代器模式,将遍历集合的操作与集合的底层实现的结构分离。
Iterator:迭代器接口,定义了两个方法。next()方法返回当前位置的元素并将位置移至下一位;hasNext()判断是否还有下一个元素。
ConcreteIterator:具体迭代器,实现了迭代器接口(Iterator)。
Aggregate:容器接口,定义了容器的基本操作:add()添加元素,remove()删除元素,iterator()获取容器的迭代器。
ConcreteAggregate:具体容器类。
首先,我们看下java.util.Iterator,这就是迭代器接口,它的定义如下:
在Iterator 中定义了三个方法,比我们上面UML图中多了一个remove()方法,此方法用于将调用next()返回的对象从容器中移除。方法的定义不是重点,我们要学习的是迭代器模式的这种思想。接下来,我们再看下java.util.Collection这个接口,此接口对应的就是上面UML图中的Aggregate接口。Collection接口部分定义如下:
这里只列举了Collection的三个方法,其他的方法我们先不讨论,感兴趣的同学可以看下java.util.Collection 的源码。到目前为止,迭代器接口、容器接口我们都列举出来了,现在我们看下他们的实现类。Collection的实现类有很多,有ArrayList、LinkedList、HashSet等。这里我们以常用的ArrayList来分析,ArrayList中的add(),remove()方法的具体实现,我们不去讨论,直接看iterator()方法
从代码中可以看出:iterator()方法返回了一个ArrayListIterator对象,而这个ArrayListIterator是ArrayList的内部类,它实现了Iterator接口。至于三个方法的具体实现,它们会涉及到ArrayList底层实现的内容,这里也不做讨论了,有时间以后再写下有关ArrayList底层实现的原理的文章。
最后总结下,迭代器模式让我们能访问容器中每个元素,而又不暴露其内部的表示;这种模式把遍历的任务放在了迭代器上,而不是容器上,这样简化了容器的接口和实现,也让责任各得其所。
我们知道对容器对象的访问必然会涉及到遍历操作,一般情况下,我们的做法是将遍历的方法封装在容器中,但是这样会带来新的问题:容器类不仅要维护自身内部的数据元素,还要对外提供遍历的接口方法,这样不但显得类很臃肿,同时也违背了抽象编程原则。为了解决上面的缺点,我们可以采用迭代器模式,将遍历集合的操作与集合的底层实现的结构分离。
一,定义:
迭代器模式:提供一种方法顺序访问一个容器中的各个元素,而又不需要暴露该对象的内部表示。二,UML类图
迭代器模式UML类图如下:Iterator:迭代器接口,定义了两个方法。next()方法返回当前位置的元素并将位置移至下一位;hasNext()判断是否还有下一个元素。
ConcreteIterator:具体迭代器,实现了迭代器接口(Iterator)。
Aggregate:容器接口,定义了容器的基本操作:add()添加元素,remove()删除元素,iterator()获取容器的迭代器。
ConcreteAggregate:具体容器类。
三,实例
上面我们提到,Java集合类就用到迭代器模式,这里我们就以集合的源码来举例说明迭代器模式的使用。首先,我们看下java.util.Iterator,这就是迭代器接口,它的定义如下:
public interface Iterator<E> { /** * Returns true if there is at least one more element, false otherwise. * @see #next */ public boolean hasNext(); /** * Returns the next object and advances the iterator. * * @return the next object. * @throws NoSuchElementException * if there are no more elements. * @see #hasNext */ public E next(); /** * Removes the last object returned by {@code next} from the collection. * This method can only be called once between each call to {@code next}. * * @throws UnsupportedOperationException * if removing is not supported by the collection being * iterated. * @throws IllegalStateException * if {@code next} has not been called, or {@code remove} has * already been called after the last call to {@code next}. */ public void remove(); }
在Iterator 中定义了三个方法,比我们上面UML图中多了一个remove()方法,此方法用于将调用next()返回的对象从容器中移除。方法的定义不是重点,我们要学习的是迭代器模式的这种思想。接下来,我们再看下java.util.Collection这个接口,此接口对应的就是上面UML图中的Aggregate接口。Collection接口部分定义如下:
public interface Collection<E> extends Iterable<E> { /** * Attempts to add {@code object} to the contents of this * {@code Collection} (optional). * * After this method finishes successfully it is guaranteed that the object * is contained in the collection. * * If the collection was modified it returns {@code true}, {@code false} if * no changes were made. * * An implementation of {@code Collection} may narrow the set of accepted * objects, but it has to specify this in the documentation. If the object * to be added does not meet this restriction, then an * {@code IllegalArgumentException} is thrown. * * If a collection does not yet contain an object that is to be added and * adding the object fails, this method <i>must</i> throw an appropriate * unchecked Exception. Returning false is not permitted in this case * because it would violate the postcondition that the element will be part * of the collection after this method finishes. * * @param object * the object to add. * @return {@code true} if this {@code Collection} is * modified, {@code false} otherwise. * * @throws UnsupportedOperationException * if adding to this {@code Collection} is not supported. * @throws ClassCastException * if the class of the object is inappropriate for this * collection. * @throws IllegalArgumentException * if the object cannot be added to this {@code Collection}. * @throws NullPointerException * if null elements cannot be added to the {@code Collection}. */ public boolean add(E object); /*** * 其他方法省略,有兴趣的可以看下源码 */ /** * Returns an instance of {@link Iterator} that may be used to access the * objects contained by this {@code Collection}. The order in which the elements are * returned by the iterator is not defined. Only if the instance of the * {@code Collection} has a defined order the elements are returned in that order. * * @return an iterator for accessing the {@code Collection} contents. */ public Iterator<E> iterator(); /** * Removes one instance of the specified object from this {@code Collection} if one * is contained (optional). The element {@code elem} that is removed * complies with {@code (object==null ? elem==null : object.equals(elem)}. * * @param object * the object to remove. * @return {@code true} if this {@code Collection} is modified, {@code false} * otherwise. * @throws UnsupportedOperationException * if removing from this {@code Collection} is not supported. * @throws ClassCastException * if the object passed is not of the correct type. * @throws NullPointerException * if {@code object} is {@code null} and this {@code Collection} * doesn't support {@code null} elements. */ public boolean remove(Object object);
这里只列举了Collection的三个方法,其他的方法我们先不讨论,感兴趣的同学可以看下java.util.Collection 的源码。到目前为止,迭代器接口、容器接口我们都列举出来了,现在我们看下他们的实现类。Collection的实现类有很多,有ArrayList、LinkedList、HashSet等。这里我们以常用的ArrayList来分析,ArrayList中的add(),remove()方法的具体实现,我们不去讨论,直接看iterator()方法
@Override public Iterator<E> iterator() { return new ArrayListIterator(); } private class ArrayListIterator implements Iterator<E> { /** Number of elements remaining in this iteration */ private int remaining = size; /** Index of element that remove() would remove, or -1 if no such elt */ private int removalIndex = -1; /** The expected modCount value */ private int expectedModCount = modCount; public boolean hasNext() { return remaining != 0; } @SuppressWarnings("unchecked") public E next() { ArrayList<E> ourList = ArrayList.this; int rem = remaining; if (ourList.modCount != expectedModCount) { throw new ConcurrentModificationException(); } if (rem == 0) { throw new NoSuchElementException(); } remaining = rem - 1; return (E) ourList.array[removalIndex = ourList.size - rem]; } public void remove() { Object[] a = array; int removalIdx = removalIndex; if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } if (removalIdx < 0) { throw new IllegalStateException(); } System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining); a[--size] = null; // Prevent memory leak removalIndex = -1; expectedModCount = ++modCount; } }
从代码中可以看出:iterator()方法返回了一个ArrayListIterator对象,而这个ArrayListIterator是ArrayList的内部类,它实现了Iterator接口。至于三个方法的具体实现,它们会涉及到ArrayList底层实现的内容,这里也不做讨论了,有时间以后再写下有关ArrayList底层实现的原理的文章。
最后总结下,迭代器模式让我们能访问容器中每个元素,而又不暴露其内部的表示;这种模式把遍历的任务放在了迭代器上,而不是容器上,这样简化了容器的接口和实现,也让责任各得其所。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序