Digester:一个通用xml引擎的设计剖析

   一:Digester介绍

   Digester是Jakarta 子项目Commons下的一个模块,支持基于规则的对任意XML文档的处理。它最初是Structs项目的

一部分,后因其通用性而划归Commons.

   本文不是描述Digester如何使用,而是深入分析Digester的源码,对其设计进行分析,从而从中学到设计方法和一些设计

理念,正所谓“授人鱼,不如授人以渔”。

 

   二:不好的设计

  Digester要解决的问题看起来很简单:根据xml文件定义,来生成指定的对象。估计大部分人的第一反应就是if-else,由于

xml类似是树形结构的,因此为了完成一个xml文件的解析,需要if-else加上递归才能完成一个xml文件的解析,例如下面的

xml文件,于下面的写法:

                                                if( element = "book")

                                                {

                                                      processBook();

                                                 }

 

                                                if( element = "name ")

                                                {

                                                      processName();

                                                 }

                                                 .....................................

 

    从功能上来说,这样也确实是能够实现功能,但从设计角度来说,这样几乎是没有任何设计,为什么呢?

    这样的设计存在的主要问题如下:

    1)代码和xml结构和元素绑定,一旦xml结构变化,或者element的处理变化,解析代码就需要跟着调整;

    2)由于上面问题,导致这个所谓的xml引擎无法被重用,每个不同的项目采用不同的xml文件,都需要重新编写代码。

    总结来说,这个设计就是没有任何封装,无法重用,不能适应任何变化。

 

   三:Digester设计分析

    下面我们看看Digester是如何设计的。

    通过上面的一个样例分析,我们知道设计一个通用xml引擎要面临的设计问题有:

1xml文档格式不定;(2)每个xml对象的处理方式是可以变化的。

  那么,Digester是如何解决这两个问题呢?

 

  我们首先来看Digester的运行机制,如下是Digester的类结构图:

  

     Digester:一个通用xml引擎的设计剖析

 

 

1)  首先,Client需要创建一个Digester对象;

2)  然后,Client必须根据自己的xml格式来添加所有的Rule

3)  添加完Rule后,Client调用Digesterparse操作来解析xml文件。

4)  Digester实现了SAX的接口,解析时遇到具体的xml对象时会调用starElement等接口函数

5)  在这些SAX接口函数中,会扫描规则链rules(图中的RulesBase对象),找到匹配规则,规则匹配一般都是根据具体的元素名称来进行匹配。

6)  找到对应的rule后,依次执行rule。这里starElement对应的是begin操作,endElement对应的是end操作。具体要

    做的事情都在每个rule的begin、body、end函数中。

7)  文档结束后,会执行所有rulefinish函数。

 

从以上的运行过程可以看出,Digester为了解决面临的两个问题,采用了巧妙的设计方法:

(1)xml格式变化:Digester把这个变化抛给具体用户去解决,用户在使用Digester之前必须自己根据自己的

xml文件格式来构造规则链,Digester只提供构造规则链的手段,体现了有所为有所不为的设计思想。

2)“处理方式变化”的问题,Digester将“处理方式”抽象为“规则rule”,一个规则对应一个处理方式。

Digester提供了通用的缺省的Rule,如果用户觉得Digester提供的规则不满足自己的要求,可以自己另外定制,样例

dbinsert就体现了这种情况。

 

有了以上的设计,Digester完全就是一个通用的xml引擎了,只要你根据自己的应用写对应的Rule就OK了,

个人想到的应用有(以下仅为推测,没有真正考核过是否是这样实现):

1)根据xml文件创建对象:例如struts,Android中由xml定义view;

2)根据xml文件执行操作:例如Ant,数据库操作;

3)根据xml文件定义流程:例如数据流、业务流处理;

........................(其它请大家自己发散了:-P)

 

四:Digester设计总结

    大部分人可能都知道设计模式中两个重要的设计原则“基于接口编程”和“封装变化”,但实际应用中如

体现呢?Digester为我们提供了很好的样例。

(1)基于接口编程:Digester的框架类都是接口或者虚类,例如Rules、Rule;

(2)封装变化:将具体的处理抽象为Rule,将xml的结构由用户去构造(因为这个无法抽象)。

顺便翻了一下《设计模式》,觉得Digester这种设计方法对应设计模式中的“策略模式”。

 

附:Digester源码CSDN上就有。

 

  

 

上一篇:数据库范式:掀起你的盖头来(3)


下一篇:3年Java开发6个点搞定高并发系统面试疑惑