副标题#e#
一、引言
迭代这个名词对付熟悉Java的人来说绝对不生疏。我们经常利用JDK提供的迭代接口举办java collection的遍历:
Iterator it = list.iterator();
while(it.hasNext()){
//using “it.next();”do some businesss logic
}
而这就是关于迭代器模式应用很好的例子。
二、界说与布局
迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的界说为:提供一种要了解见一个容器(container)工具中各个元素,而又不需袒露该工具的内部细节。
从界说可见,迭代器模式是为容器而生。很明明,对容器工具的会见一定涉及到遍历算法。你可以一股脑的将遍历要领塞到容器工具中去;可能基础不去提供什么遍历算法,让利用容器的人本身去实现去吧。这两种环境仿佛都可以或许办理问题。
然而在前一种环境,容器遭受了过多的成果,它不只要认真本身“容器”内的元素维护(添加、删除等等),并且还要提供遍历自身的接口;并且由于遍历状态生存的问题,不能对同一个容器工具同时举办多个遍历。第二种方法倒是省事,却又将容器的内部细节袒露无遗。
而迭代器模式的呈现,很好的办理了上面两种环境的漏洞。先来看下迭代器模式的真脸孔吧。
迭代器模式由以下脚色构成:
1)迭代器脚色(Iterator):迭代器脚色认真界说会见和遍历元素的接口。
2)详细迭代器脚色(Concrete Iterator):详细迭代器脚色要实现迭代器接口,并要记录遍历中的当前位置。
3)容器脚色(Container):容器脚色认真提供建设详细迭代器脚色的接口。
4)详细容器脚色(Concrete Container):详细容器脚色实现建设详细迭代器脚色的接口??这个详细迭代器脚色于该容器的布局相关。
迭代器模式的类图如下:
从布局上可以看出,迭代器模式在客户与容器之间插手了迭代器脚色。迭代器脚色的插手,就可以很好的制止容器内部细节的袒露,并且也使得设计标记“单一职责原则”。
留意,在迭代器模式中,详细迭代器脚色和详细容器脚色是耦合在一起的??遍历算法是与容器的内部细节细密相关的。为了使客户措施从与详细迭代器脚色耦合的逆境中离开出来,制止详细迭代器脚色的改换给客户措施带来的修改,迭代器模式抽象了详细迭代器脚色,使得客户措施更具一般性和重用性。这被称为多态迭代。
#p#副标题#e#
三、举例
由于迭代器模式自己的划定较量松散,所以详细实现也就八门五花。我们在此仅举一例,基础不能将实现方法一一泛起。因此在举例前,我们先来罗列下迭代器模式的实现方法。
1.迭代器脚色界说了遍历的接口,可是没有划定由谁来节制迭代。在Java collection的应用中,是由客户措施来节制遍历的历程,被称为外部迭代器;尚有一种实现方法即是由迭代器自身来节制迭代,被称为内部迭代器。外部迭代器要比内部迭代器机动、强大,并且内部迭代器在java语言情况中,可用性很弱。
2.在迭代器模式中没有划定谁来实现遍历算法。仿佛理所虽然的要在迭代器脚色中实现。因为既便于一个容器上利用差异的遍历算法,也便于将一种遍历算法应用于差异的容器。可是这样就粉碎掉了容器的封装??容器脚色就要果真本身的私有属性,在java中便意味着向其他类果真了本身的私有属性。
那我们把它放到容器脚色里来实现好了。这样迭代器脚色就被排斥为仅仅存放一个遍历当前位置的成果。可是遍历算法便和特定的容器牢牢绑在一起了。
而在Java Collection的应用中,提供的详细迭代器脚色是界说在容器脚色中的内部类。这样便掩护了容器的封装。可是同时容器也提供了遍历算法接口,你可以扩展本身的迭代器。
好了,我们来看下Java Collection中的迭代器是怎么实现的吧。
//迭代器脚色,仅仅界说了遍历接口
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
public abstract class AbstractList extends AbstractCollection
implements List {
……
//这个即是认真建设详细迭代器脚色的工场要领
public Iterator iterator() {
return new Itr();
}
//作为内部类的详细迭代器脚色
private class Itr implements Iterator {
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public Object next() {
checkForComodification();
try {
Object next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
#p#分页标题#e#
至于迭代器模式的利用。正如引言中所列那样,客户措施要先获得详细容器脚色,然后再通过详细容器脚色获得详细迭代器脚色。这样便可以利用详细迭代器脚色来遍历容器了……
四、实现本身的迭代器
在实现本身的迭代器的时候,一般要操纵的容器有支持的接谈锋可以。并且我们还要留意以下问题:
在迭代器遍历的进程中,通过该迭代器举办容器元素的增减操纵是否安详呢?
在容器中存在复合工具的环境,迭代器奈何才气支持深层遍历和多种遍历呢?
以上两个问题对付差异布局的容器脚色,各不沟通,值得思量。
五、合用环境
由上面的报告,我们可以看出迭代器模式给容器的应用带来以下长处:
1)支持以差异的方法遍历一个容器脚色。按照实现方法的差异,结果上会有不同。
2)简化了容器的接口。可是在java Collection中为了提高可扩展性,容器照旧提供了遍历的接口。
3)对同一个容器工具,可以同时举办多个遍历。因为遍历状态是生存在每一个迭代器工具中的。
由此也能得出迭代器模式的合用范畴:
1)会见一个容器工具的内容而无需袒露它的内部暗示。
2)支持对容器工具的多种遍历。
3)为遍历差异的容器布局提供一个统一的接口(多态迭代)。