细说迭代器模式
提示:
博主:章飞 _906285288的博客
博客地址:http://blog.csdn.net/qq_29924041
细说迭代器模式
记得刚开始在学习se的中的集合的时候,有个绕不开的坎,就是迭代器,几乎所有的集合类都是Iterator接口的子类,在遍历的时候不需要关系其遍历的规则和顺序情况,那些是针对已有集合进行的迭代,但是如果在实际应用过程中,需要对某一类对象集进行操作的时候,能不能应用这种设计模式呢??下面来简单讲解下
定义
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。其实主要的意思就是迭代器模式它提供了一种方法,可以访问一个容器对象中的各个元素。目前来看,这种迭代器模式,使用场景并不是特别多。
迭代器对象是为了容器进行服务的,什么是容器??Collection集合类型,Set类型都是容器的一种。而迭代器主要也就是为了遍历它们而诞生的。
UML模型
从迭代器对象中可以看到有以下几种角色
1:Iterator 迭代器对象,负责定义访问和遍历使用的
2:ConcreteIterator 具体的迭代器对象,负责实现迭代器,实现遍历使用的
3:Aggregate抽象的容器,创建具体的迭代器使用的
4:Concrete Aggregate具体的容器,实现容器接口,创建出容纳迭代器的对象
场景
场景一
本案例来自设计模式之禅,就是怎么去遍历一个项目,通常是有两种写法, 一种是直接在使用的时候没有封装思想,直接将项目放入集合中进行遍历,这种方法最简单和显而易见。另外一种方法其实就是迭代器模式,本身其实就将对象封装成了一个容器,通过迭代器来对容器内部的信息进行访问。
场景二
在java的集合类的体系中,迭代器的使用时无处不在的,从源码的角度简单分析下迭代器,其实在源码中主要包括了Collection接口,Iterable接口,Iterator接口,剩下的其实都是一些具体的实现类对象。
代码
代码一
package src.com.zzf.designpattern.iteratorpattern.demo2;
/**
* 顶层的迭代器实现类
* @author zhouzhangfei`在这里插入代码片`
*
*/
public interface Iterator {
public boolean hasNext();
public Object next();
public void remove();
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
/**
* 此类主要是迭代器的接口适配器类,为了避免需要特殊的方法会污染顶层的迭代器接口
* @author zhouzhangfei
*
*/
public interface IProjectIterator extends Iterator {
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
/**
* 抽象的容器,在这里主要是针对项目本身来说的,也就是说这是一个抽象的项目容器
* @author zhouzhangfei
*
*/
public interface IProject {
public String getProjectInfo();
public void add(String name,int num,int cost);
public IProjectIterator iterator();
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
import java.util.ArrayList;
public class Project2 implements IProject{
//定义一个项目列表,说有的项目都放在这里
private ArrayList<IProject> projectList = new ArrayList<IProject>();
//项目名称
private String name = "";
//项目成员数量
private int num = 0;
//项目费用
private int cost = 0;
private Project2(String name,int num,int cost) {
this.name = name;
this.num = num;
this.cost = cost;
}
public Project2() {
// TODO Auto-generated constructor stub
}
public String getProjectInfo() {
String info = "";
//获得项目的名称
info = info+ "项目名称是:" + this.name;
//获得项目人数
info = info + "\t项目人数: "+ this.num;
//项目费用
info = info+ "\t 项目费用:"+ this.cost;
return info;
}
public void add(String name, int num, int cost) {
// TODO Auto-generated method stub
this.projectList.add(new Project2(name,num,cost));
}
public IProjectIterator iterator() {
// TODO Auto-generated method stub
return new ProjectIterator(projectList);
}
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
import java.util.ArrayList;
/**
* 项目容器的实现类
* @author zhouzhangfei
*
*/
public class ProjectIterator implements IProjectIterator{
//所有的项目都放在这里ArrayList中
private ArrayList<IProject> projectList = new ArrayList<IProject>();
private int currentItem = 0;
//构造函数传入projectList
public ProjectIterator(ArrayList<IProject> projectList){
this.projectList = projectList;
}
public boolean hasNext() {
// TODO Auto-generated method stub
boolean b = true;
if (this.currentItem >= projectList.size() || this.projectList.get(currentItem) == null) {
b = false;
}
return b;
}
public Object next() {
// TODO Auto-generated method stub
return (IProject)this.projectList.get(this.currentItem++);
}
public void remove() {
// TODO Auto-generated method stub
}
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
public class Boss {
public static void main(String[] args) {
IProject project = new Project2();
//增加星球大战项目
project.add("星球大战项目ddddd",10,100000);
//增加扭转时空项目
project.add("扭转时空项目",100,10000000);
//增加超人改造项目
project.add("超人改造项目",10000,1000000000);
//这边100个项目
for(int i=4;i<104;i++){
project.add("第"+i+"个项目",i*5,i*1000000);
}
IProjectIterator projectIterator = project.iterator();
while(projectIterator.hasNext()){
IProject p = (IProject)projectIterator.next();
System.out.println(p.getProjectInfo());
}
}
}
代码二
以下代码主要是从源码角度查看下系统的实现
Iterable接口,中
public interface Iterable<T> {
//创建一个迭代器
Iterator<T> iterator();
/**
* Performs the given action for each element of the {@code Iterable}
* until all elements have been processed or the action throws an
* exception. Unless otherwise specified by the implementing class,
* actions are performed in the order of iteration (if an iteration order
* is specified). Exceptions thrown by the action are relayed to the
* caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* for (T t : this)
* action.accept(t);
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
/**
* Creates a {@link Spliterator} over the elements described by this
* {@code Iterable}.
*
* @implSpec
* The default implementation creates an
* <em><a href="Spliterator.html#binding">early-binding</a></em>
* spliterator from the iterable's {@code Iterator}. The spliterator
* inherits the <em>fail-fast</em> properties of the iterable's iterator.
*
* @implNote
* The default implementation should usually be overridden. The
* spliterator returned by the default implementation has poor splitting
* capabilities, is unsized, and does not report any spliterator
* characteristics. Implementing classes can nearly always provide a
* better implementation.
*
* @return a {@code Spliterator} over the elements described by this
* {@code Iterable}.
* @since 1.8
*/
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
具体的迭代器的接口,可以看到,它提供的方法hasNext,next,remove等
/*
public interface Iterator<E> {
/**
* Returns {@code true} if the iteration has more elements.
* (In other words, returns {@code true} if {@link #next} would
* return an element rather than throwing an exception.)
*
* @return {@code true} if the iteration has more elements
*/
boolean hasNext();
/**
* Returns the next element in the iteration.
*
* @return the next element in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
E next();
/**
* Removes from the underlying collection the last element returned
* by this iterator (optional operation). This method can be called
* only once per call to {@link #next}. The behavior of an iterator
* is unspecified if the underlying collection is modified while the
* iteration is in progress in any way other than by calling this
* method.
*
* @implSpec
* The default implementation throws an instance of
* {@link UnsupportedOperationException} and performs no other action.
*
* @throws UnsupportedOperationException if the {@code remove}
* operation is not supported by this iterator
*
* @throws IllegalStateException if the {@code next} method has not
* yet been called, or the {@code remove} method has already
* been called after the last call to the {@code next}
* method
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* while (hasNext())
* action.accept(next());
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
结合类接口Collection,可以看到Collections继承自Iteratable接口允许创建一个Iterator接口对象,并且补充了很多接口对象的方法。而Collection的子类有Set,List,Map.SortedSet等等。说明其子类也都具有相同的特性
package java.util;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* @author Josh Bloch
* @author Neal Gafter
* @see Set
* @see List
* @see Map
* @see SortedSet
* @see SortedMap
* @see HashSet
* @see TreeSet
* @see ArrayList
* @see LinkedList
* @see Vector
* @see Collections
* @see Arrays
* @see AbstractCollection
* @since 1.2
*/
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
// Modification Operations
boolean add(E e);
boolean remove(Object o);
// Bulk Operations
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
/**
* Creates a {@link Spliterator} over the elements in this collection.
*
* Implementations should document characteristic values reported by the
* spliterator. Such characteristic values are not required to be reported
* if the spliterator reports {@link Spliterator#SIZED} and this collection
* contains no elements.
*
* <p>The default implementation should be overridden by subclasses that
* can return a more efficient spliterator. In order to
* preserve expected laziness behavior for the {@link #stream()} and
* {@link #parallelStream()}} methods, spliterators should either have the
* characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
* <em><a href="Spliterator.html#binding">late-binding</a></em>.
* If none of these is practical, the overriding class should describe the
* spliterator's documented policy of binding and structural interference,
* and should override the {@link #stream()} and {@link #parallelStream()}
* methods to create streams using a {@code Supplier} of the spliterator,
* as in:
* <pre>{@code
* Stream<E> s = StreamSupport.stream(() -> spliterator(), spliteratorCharacteristics)
* }</pre>
* <p>These requirements ensure that streams produced by the
* {@link #stream()} and {@link #parallelStream()} methods will reflect the
* contents of the collection as of initiation of the terminal stream
* operation.
*
* @implSpec
* The default implementation creates a
* <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
* from the collections's {@code Iterator}. The spliterator inherits the
* <em>fail-fast</em> properties of the collection's iterator.
* <p>
* The created {@code Spliterator} reports {@link Spliterator#SIZED}.
*
* @implNote
* The created {@code Spliterator} additionally reports
* {@link Spliterator#SUBSIZED}.
*
* <p>If a spliterator covers no elements then the reporting of additional
* characteristic values, beyond that of {@code SIZED} and {@code SUBSIZED},
* does not aid clients to control, specialize or simplify computation.
* However, this does enable shared use of an immutable and empty
* spliterator instance (see {@link Spliterators#emptySpliterator()}) for
* empty collections, and enables clients to determine if such a spliterator
* covers no elements.
*
* @return a {@code Spliterator} over the elements in this collection
* @since 1.8
*/
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
}
最后在附上一张集合的关系图
图片摘自https://blog.csdn.net/lyabc123456/article/details/80390619
很容易可以看出迭代器的重要性。
基于UML的代码
package src.com.zzf.designpattern.iteratorpattern.demo3;
/**
* 抽象的迭代器接口
* @author zhouzhangfei
*
*/
public interface Iterator {
//下一个元素
public Object next();
//判断是否含有下一个
public boolean hasNext();
//移除当前的元素
public boolean remove();
}
package src.com.zzf.designpattern.iteratorpattern.demo3;
import java.util.Vector;
/**
* 具体的迭代器的实现类
* @author zhouzhangfei
*
*/
public class ConcreteIterator implements Iterator {
private Vector<Object> mVector = new Vector<>();
private int cursor = 0;
public ConcreteIterator(Vector vector){
this.mVector = vector;
}
@Override
public Object next() {
// TODO Auto-generated method stub
Object result = null;
if(this.hasNext()){
result = this.mVector.get(this.cursor++);
}else{
result = null;
}
return result;
}
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
if(this.cursor == this.mVector.size()){
return false;
}else{
return true;
}
}
@Override
public boolean remove() {
// TODO Auto-generated method stub
this.mVector.remove(this.cursor);
return false;
}
}
package src.com.zzf.designpattern.iteratorpattern.demo3;
/**
* 抽象的容器接口
* @author zhouzhangfei
*
*/
public interface Aggregate {
/**
* 增加元素
* @param object
*/
public void add(Object object);
/**
* 减少元素
* @param object
*/
public void remove(Object object);
/**
* 创建迭代器对象
* @return
*/
public Iterator iterator();
}
package src.com.zzf.designpattern.iteratorpattern.demo3;
import java.util.Vector;
/**
* 具体的容器接口
* @author zhouzhangfei
*
*/
public class ConcreteAggregate implements Aggregate{
private Vector mVector = new Vector<>();
@Override
public void add(Object object) {
// TODO Auto-generated method stub
mVector.add(object);
}
@Override
public void remove(Object object) {
// TODO Auto-generated method stub
mVector.remove(object);
}
@Override
public Iterator iterator() {
// TODO Auto-generated method stub
return new ConcreteIterator(mVector);
}
}
package src.com.zzf.designpattern.iteratorpattern.demo3;
/**
* 测试类
* @author zhouzhangfei
*
*/
public class Client {
public static void main(String[] args) {
Aggregate mAggregate = new ConcreteAggregate();
mAggregate.add("123");
mAggregate.add("abc");
mAggregate.add("abcd");
mAggregate.add("abcde");
mAggregate.add("abcdef");
mAggregate.add("abcdefg");
Iterator iterator = mAggregate.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
迭代器模式应用和注意事项
迭代器模式使用时要明确你是要单独操作你的对象还是去操作对象的容器。
其实在实际开发中自己去写一个迭代器模式的场景不多。而且java的jdk中其实已经为我们准备好了迭代器,如果自己再去创造的话,显得有点多余了,不过这个设计模式依旧相当的重要
欢迎继续访问,我的博客