论坛首页 Java企业应用论坛

主控Iterator模式与被动Visitor模式

浏览 3355 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-09-11  
有朋友问我MeteorTL(http://www.meteortl.org)优势列表中的主控Iterator模式优势具体指什么。

buaawhl的帖子已经分析很多:
http://www.iteye.com/topic/21293

我再补充的说一下:

Visitor模式使用最多的时候是处理合成模式的树结构,
估计是受[GoF95]的影响,书中提倡将树结构的表示与逻辑分开,
这样不同的Visitor对同一树结构可以做不同的事,以达到重用及扩展,
如:将一个模板解析成树后,针对同一树结构表示,EvaluationVisitor可以输出模板结果,
BackupVisitor可以备份树,CountVisitor可以统计树中的节点...
这种思想很好,但实际中,如果以Visitor风格导出API,API很难理解,也很难使用,
因为扩展方很被动,并不是每一次使用树都是要做遍历操作的,
而且,Visitor通常会很大,因为它要处理所有节点类型,通常是用很多类型重载的visit方法,
再者,往往最后都是,整个系统只有一个Visitor,因为Visitor的实现很复杂,

其实Visitor模式的优势Iterator模式都能作到,
如果改用Iterator模式,可以使用解释器模式的层级调用,
在主控函数中回调Handler,以及发布访问前后Event,再加上个AOP拦截器链,
扩展者可以只Handle某一个节点类型的处理,也可通过监听事件处理周边事物,或者通过AOP统一处理所有节点,
灵活性远远超过Visitor模式,

如:FreeMarker, Velocity都使用了Visitor模式,扩展性是极其受限的,这可能是由于它们都使用JavaCC作为解板工具,而JavaCC生成Visitor模式的解析代码,有点被迫使用。
而MeteorTL(http://www.meteortl.org)则使用Iterator模式,在扩展性方面就很有优势。

节点的扩展是经常用到的,举个例对比一下:

Visitor模式的:
public class NodeHandler {

	public static final int DO_BODY = 1;

	...

	// 因为Node是被动的,所以返回一个数字控制Visitor的遍历路线,
	// 除非只作正规的前序遍历,就能满足你所有的需求,则可以不返回值,
	public int handle() {
		// 返回1,继续访问内部节点
		// 返回2,继续访问下一兄弟节点
		// 返回3,表示重复当前节点
		// 返回4,表示跳过后面所有节点
		// ...
	}

}

看到上面的方式,估计写过JSP Tag Lib的朋友印象深刻,doStrat, doEnd就是这么做的。
调用者(JSP引擎相当于调用者)也很费神,要一个个判断状态位,if...else...估计是一大堆。
如果你的需求超过了上面的1, 2, 3, 4...,那就没办法,等新版本发布可能会有:-)


Iterator模式的:
public class NodeHandler {

	// 每个节点持有自己的子节点,解析树时置入
	Node[] childNodes;

	public void handle() {
		// 1.如果要忽略子节点,直接将函数留空

		// 2.如果要运行字节点
		handleChildNodes();

		// 3.如果要迭代子节点n次
		for (int i = 0, i < n; i ++) {
			handleChildNodes();
		}
	}

	private void handleChildNodes() {
		for(int i = 0, n = childNodes.length; i < n; i ++) {
			childNodes[i].handle();
		}
	}

}

调用者只需要调用根节点的handle(),根节点将调用其所有子节点,层级调用下去就完成了遍历,需不需要调用下级节点完全是主控的。

   发表时间:2008-01-12  
对楼主的项目不熟悉。
Visitor模式确实很不好,Visitor接口要依赖于被访问的各个具体子类,请楼主讲解一下Iterator模式如何替代Visitor模式并允许被访问接口新增子类的,谢谢!
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics