Iterator模式和论坛的浏览
Iterator模式用来分离数据结构和遍历算法,降低两者之间的耦合度,以使得同一个数据结构用不同的算法遍历时,仍能够具有相同的接口,另一方面,Iterator模式使得当改换遍历算法后,不需要更改程序的代码。
在Java的JDK中本身就定义有一个Iterator接口,在Iterator接口中仅仅定义了三个方法,hasNext()判断是否遍历完最后一个元素,next()方法返回要遍历的数据结构中一个对象,remove()则删除当前对象。Jive中使用IteratorProxy抽象类继承了这一接口。这儿Proxy的含义和上面一样,也就是说,这个IteratorProxy出了会实现Iterator的遍历功能外,还会有代理权限控制的功能。
对于论坛中的基本对象Forum,ForumThread,ForumMessage,Group,User都有相应的遍历器。比如对应于Forum接口有ForumIteratorProxy对象。这个ForumIteratorProxy遍历器就相当于一个封装了一系列Forum对象的集合类,通过定义好的接口hasNext()和next()可以方便的遍历这个集合,而并不需要知道是如何遍历这个集合的。遍历的算法可能很简单,也可能很复杂,但是对于外部的客户而言,这并没有任何的区别。
而对于论坛中具体的遍历方法,这取决于具体的实现,在Jive中给出的是数据库的实现。
我们就以MessageIteratorProxy为例,来讲解Iterator模式的用法。
DbThreadIterator对象实现了Iterator接口,是对于一个Thread中所有Message的遍历器,我们来看看它是如何实现的。
hasNext()判断在这个Thread中是不是还有下一条Message:
public boolean hasNext() {
if (currentIndex+1 >= messages.length) {
return false;
}
return true;
}
next()方法从数据库中取出与在这个Thread中的下一条Message:
public Object next() throws java.util.NoSuchElementException {
ForumMessage message = null;
if (nextMessage != null) {
message = nextMessage;
nextMessage = null;
}
else {
message = getNextMessage();
if (message == null) {
throw new java.util.NoSuchElementException();
}
}
return message;
}
这样,通过对数据库的操作,DbThreadIterator实现了对一个Thread中所有Message遍历的方法。
再ForumThread接口中有messages()方法,返回在这个Thread中的所有Message的一个遍历器(Iterator),实际上也就是返回了一个Message的集合:
public Iterator messages();
在DbForumThread中实现了这个方法:
public Iterator messages() {return new DbThreadIterator(this);}
从DbForumThread的messages()方法中所返回的就是这个Thread中所有Message的一个遍历器,通过这个遍历器,我们就可以访问Thread中的所有的Message了。当然,事情还没有完,由于权限的问题,我们还需要构造这个遍历器的Proxy对象,然后通过这个Proxy对象来访问遍历器。
下面的类图给出了在Jive中Iterator模式的实现方法:
图5:Jive中Iterator模式的实现
在Jive中,因为在一个Thread之下,Message是按树形结构组织的,因而,当需要层级表示一个Thread中的Message之间的关系的时候,仅仅用上面讲到的线性的Iterator是不够的。这时候,对Iterator的概念进行推广,就引入了TreeWalker接口。
顾名思义,TreeWalker提供了遍历一个树和存取树上节点的方法:
public interface TreeWalker {
public ForumMessage getRoot();
public ForumMessage getChild(ForumMessage parent, int index);
public int getChildCount(ForumMessage parent);
public int getRecursiveChildCount(ForumMessage parent);
public int getIndexOfChild(ForumMessage parent, ForumMessage child);
public boolean isLeaf(ForumMessage node);
}
TreeWalker只是Iterator的简单推广,并没有Iterator应用的那么广泛,而且,也可以很容易的在TreeWalker上面在套一层Iterator的借口,让它在某些情况下行使Iterator的职责。这儿就不再多讨论了。