閱讀788 返回首頁    go 技術社區[雲棲]


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

 

 

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上就有。

 

  

 

最後更新:2017-04-02 00:06:42

  上一篇:go 如何通過查詢分析器清除sql server數據庫日誌
  下一篇:go javascript 類式繼承與原型繼承