设计模式——迭代器模式
我尽量不打错别字,用词准确,不造成阅读障碍。
很简单的一种设计模式,因为其在数据、集合、列表等领域被广泛使用,所以已经被各大语言收入其中进行封装;
平常我们遍历一个LinkList的时候一般会用foreach遍历,那么foreach是怎么遍历的呢?其实是内部使用了迭代器模式实现的。
补充:遍历一个ArrayList的时候一般会用for循环,遍历一个LinkList的时候一般会用foreach遍历,网上有人做了实验,结果显示ArrayList这种数组列表循环用for比较合适,LinkList这种链列表用foreach比较合适,先不探究实验的合理性。
定义:一种顺序访问集合对象中各个元素却不用暴露该对象内部实现的表示。UML如下:
具体代码如下:
集合抽象类
public interface Aggregate {
Iterator CreateIterator();
}
具体集合类
public class ConcreteAggregate implements Aggregate {
private String[] item = new String[6];
@Override
public Iterator CreateIterator() {
return new ConcreteIterator(this);
}
public int Count() {
return item.length;
}
public Object getItem(int i) {
return item[i];
}
public void setItem(int i, String value) {
item[i] = value;
}
}
抽象迭代器
public interface Iterator {
Object First();
Object Next();
boolean IsDone();
Object CurrentItem();
}
具体迭代器类
public class ConcreteIterator implements Iterator {
private ConcreteAggregate mConcreteAggregate;
private int current = 0;
public ConcreteIterator(ConcreteAggregate concreteAggregate) {
this.mConcreteAggregate = concreteAggregate;
}
@Override
public Object First() {
return mConcreteAggregate.getItem(0);
}
@Override
public Object Next() {
current++;
if (current < mConcreteAggregate.Count()) {
return mConcreteAggregate.getItem(current);
}
return null;
}
@Override
public boolean IsDone() {
return current >= mConcreteAggregate.Count() ? true : false;
}
@Override
public Object CurrentItem() {
return mConcreteAggregate.getItem(current);
}
}
客户端代码:
public static void main(String args[]) {
ConcreteAggregate concreteAggregate = new ConcreteAggregate();
concreteAggregate.setItem(0,"1");
concreteAggregate.setItem(1,"2");
concreteAggregate.setItem(2,"3");
concreteAggregate.setItem(3,"4");
concreteAggregate.setItem(4,"5");
concreteAggregate.setItem(5,"6");
com.study.study.IteratorDemo.Iterator i = concreteAggregate.CreateIterator();
while (!i.IsDone()){
System.out.println(i.CurrentItem());
i.Next();
}
}
运行结果:
总的来说就是:分离集合对象的迭代行为,抽象出一个迭代器来负责,既可以做到不暴露集合内部结构又可以让外部代码透明访问内部集合的数据。 而且这样迭代起来很方便,比如,在上面的代码的前提下,如果你想要反向遍历数据,你可以写一个反向的具体迭代器类,然后在客户端代码出new一个新的对象就好了。如下:
//反向迭代器类
public class ConcreteIteratorDesc implements Iterator {
private ConcreteAggregate mConcreteAggregate;
private int current = 0;
public ConcreteIterator(ConcreteAggregate concreteAggregate) {
this.mConcreteAggregate = concreteAggregate;
current = this.mConcreteAggregate.Count() - 1;
}
@Override
public Object First() {
return mConcreteAggregate.getItem(this.mConcreteAggregate.Count() - 1);
}
@Override
public Object Next() {
current--;
if (current > 0) {
return mConcreteAggregate.getItem(current);
}
return null;
}
@Override
public boolean IsDone() {
return current < 0 ? true : false;
}
@Override
public Object CurrentItem() {
return mConcreteAggregate.getItem(current);
}
}
这时在客户端就可以这样访问遍历了:
com.study.study.IteratorDemo.Iterator i = concreteAggregateDesc.CreateIterator();
很方便吧,日常使用中HashMap的遍历就是使用迭代器最多,如遍历键:
Iterator iter = map.keySet().iterator();
while(iter.hasNext()){
key = (String)iter.next();
}
因为迭代器很常用,所以Java已经把它封装在语言体系中了,使用起来很方便,基本所有的集合、数组、列表等都有封装。