设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
设计模式分为三种类型,共23种。
创建型模式(5):单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
结构型模式(7):适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
行为型模式(11):(父子类)策略模式、模版方法模式,(两个类)观察者模式、迭代器模式、职责链模式、命令模式,(类的状态)状态模式、备忘录模式,(中间类) 访问者模式、中介者模式、解释器模式。
一.概述
定义
Iterator Pattern(迭代器模式):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。
Iterator Pattern:Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
结构
在迭代器模式结构中包含聚合和迭代器两个层次结构,考虑到系统的灵活性和可扩展性,在迭代器模式中应用了工厂方法模式,其模式结构如图所示:
在迭代器模式结构图中包含如下几个角色:
- Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法,例如:用于获取第一个元素的first()方法,用于访问下一个元素的next()方法,用于判断是否还有下一个元素的hasNext()方法,用于获取当前元素的currentItem()方法等,在具体迭代器中将实现这些方法。
- ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成对聚合对象的遍历,同时在具体迭代器中通过游标来记录在聚合对象中所处的当前位置,在具体实现时,游标通常是一个表示位置的非负整数。
- Aggregate(抽象聚合类):它用于存储和管理元素对象,声明一个createIterator()方法用于创建一个迭代器对象,充当抽象迭代器工厂角色。
- ConcreteAggregate(具体聚合类):它实现了在抽象聚合类中声明的createIterator()方法,该方法返回一个与该具体聚合类对应的具体迭代器ConcreteIterator实例。
在迭代器模式中,提供了一个外部的迭代器来对聚合对象进行访问和遍历,迭代器定义了一个访问该聚合元素的接口,并且可以跟踪当前遍历的元素,了解哪些元素已经遍历过而哪些没有。迭代器的引入,将使得对一个复杂聚合对象的操作变得简单。
下面我们结合代码来对迭代器模式的结构进行进一步分析。在迭代器模式中应用了工厂方法模式,抽象迭代器对应于抽象产品角色,具体迭代器对应于具体产品角色,抽象聚合类对应于抽象工厂角色,具体聚合类对应于具体工厂角色。
实现
Java平台的集合类(Collection<E>
接口)就采用了迭代器模式,该接口定义了一个接口方法 Iterator<E> iterator();
返回该集合上的迭代器。
Collection接口的实现类ArrayList,以内部类的方式实现了Iterator。另外它还提供了ListIterator的遍历方式。
public interface Iterator<E> {
boolean hasNext();
E next();
...
}
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
public Iterator<E> iterator() {
return new Itr();
}
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;
Itr() {}
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];
}
...省略好多代码
}
//另外一种迭代器遍历方式
public ListIterator<E> listIterator() {
return new ListItr(0);
}
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
...省略好多代码
}
}
二.示例
下面仿照JDK的源码实现一个简单版本的迭代器模式。
public interface MyCollection<E> {
MyIterator<E> iterator();
}
public interface MyIterator<E> {
boolean hasNext();
E next();
}
public class MyList<E> implements MyCollection<E> {
E[] elementData;
public MyList(E[] datas){
this.elementData =datas;
}
@Override
public MyIterator<E> iterator() {
return new Itr();
}
private class Itr implements MyIterator<E> {
int cursor; // index of next element to return
Itr() {
}
@Override
public boolean hasNext() {
return cursor != elementData.length;
}
@Override
public E next() {
int i = cursor;
if (i >= elementData.length)
throw new NoSuchElementException();
E[] elementData = MyList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return elementData[i];
}
}
}
public class IteratorApp {
public static void main(String[] args) {
MyList<String> list = new MyList<>(new String[] {"abc","def","hidfdf"});
MyIterator<String> itr = list.iterator();
while(itr.hasNext()) {
System.out.println(itr.next());
}
}
}
三.总结
迭代器模式的主要目的是提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
优点:
- 它支持以不同的方式遍历一个聚合对象
- 迭代器简化了聚合类,它承担了遍历集合对象的职责
- 在同一个聚合上可以有多个遍历
- 可以改进或修改内部迭代器实现而不影响客户端的使用
- 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码
适用场景:
- 迭代器模式使得访问一个聚合对象的内容而无需暴露它的内部表示,即迭代抽象。
- 系统需要支持对聚合对象的多种遍历。
- 系统需要为不同的聚合结构提供一个统一的接口。
参考电子书下载:设计模式的艺术–软件开发人员内功修炼之道_刘伟(2013年).pdf
《道德经》第七章:
天长,地久。天地之所以能长且久者,以其不自生也,故能长生。是以圣人后其身而身先,外其身而身存,非以其无私邪?故能成其私。
译文:天长地久,天地所以能长久存在,是因为它们不为了自己的生存而自然地运行着,所以能够长久生存。因此,有道的圣人遇事谦退无争,反而能在众人之中领先;将自己置于度外,反而能保全自身生存。这不正是因为他无私吗?所以能成就他的自身。