馮靈凱
文檔應(yīng)用程序的應(yīng)用非常廣泛,如一般公眾使用的Office辦公軟件套件、各種行業(yè)的專業(yè)的編輯器等。所以不斷有學(xué)者對這些應(yīng)用的相關(guān)技術(shù)進(jìn)行了研究,并取得了很多有意義的成果。傳統(tǒng)的方法要實(shí)現(xiàn)不同的文檔類型的應(yīng)用程序,需要分別開發(fā)不同的操作行為接口,不僅工作量大,有重復(fù)冗余的工作,而且開發(fā)出來的接口很難保持一致,更難于實(shí)現(xiàn)接口重用。無法滿足同一個(gè)框架下的不同文檔操作行為必須統(tǒng)一的需求。
本文使用了一種基于模板方法[1]的文檔設(shè)計(jì)模式來定義通用文檔程序架構(gòu)中操作行為。在保證對外暴露統(tǒng)一接口的同時(shí),不同類型的文檔又可以有各自不同的隱式行為,同時(shí)增加代碼復(fù)用。
現(xiàn)在通用文檔一般分為兩大類:單文檔和多文檔。對應(yīng)的框架相應(yīng)地也可分為:單文檔程序框架、多文檔程序框架和混合文檔程序框架。對應(yīng)的操作行為相應(yīng)地也可分為:單文檔操作行為、多文檔操作行為和混合文檔操作行為。而目前對于文檔操作行為的國內(nèi)外的研究現(xiàn)狀有二大特點(diǎn):
(1) 針對單文檔操作行為的研究較多,面向多文檔操作行為的研究較少。
(2) 在同一個(gè)框架下針對只能使用一種文檔操作行為的框架研究得比較多(單文檔程序框架或多文檔程序框架),能同時(shí)使用兩種文檔操作的框架行為研究得較少(混合文檔程序框架)。
綜合國內(nèi)外的研究現(xiàn)狀,當(dāng)前關(guān)于通用文檔程序架構(gòu)中操作行為的研究有以下四個(gè)發(fā)展方向:
(1) 針對統(tǒng)一資源管理下的(如:SVN管理下的)文檔操作行為的研究[2]。
由于涉及到文檔的共享或獨(dú)占式占用,在保持服務(wù)器端文件的一致性的前提下,提供多用戶、一致的交互操作體驗(yàn)。這需要我們提供額外的技術(shù)來保證。例如可以從定義統(tǒng)一的資源管理接口上下手,在保持上層調(diào)用接口的一致性同時(shí),又可以兼容底下來自不同資源管理者提供的文檔管理操作行為服務(wù)。
(2) 虛擬單文件下的文檔操作行為相統(tǒng)一的研究。
虛擬單文件,就是要求把應(yīng)用要用到的所有文檔都?xì)w檔為一個(gè)單獨(dú)文件,而這個(gè)文件類似于一個(gè)壓縮包文件形式存在于本地或服務(wù)器磁盤上。這樣做帶來的好處是:保證所有單文件的內(nèi)部文檔結(jié)構(gòu)一致,方便做加解密和版本管理,也提高了加解密和版本管理的效率。因?yàn)槟阒灰獙挝募M(jìn)行加解密和版本管理就行了。但是要實(shí)現(xiàn)虛擬單文件,還需要很多技術(shù)來支撐。例如可以從虛擬文件壓縮[3],加解密算法和配置文件管理[4,5]等方面入手。把壓縮、加解密和讀寫配置都封裝為底層的服務(wù)組件。這樣上層應(yīng)用的操作行為可以不用關(guān)心底層具體邏輯實(shí)現(xiàn),更方便實(shí)現(xiàn)統(tǒng)一的操作行為。
(3) 對于不同版本文檔和不同版本的文檔程序,文檔操作行為相統(tǒng)一的研究。
就是說當(dāng)文檔和文檔程序都有多個(gè)版本,且它們之間的版本沒有一一對應(yīng)時(shí),怎么保證文檔操作行為的統(tǒng)一?,F(xiàn)在當(dāng)前很多應(yīng)用對于版本不一致的處理,是根據(jù)水桶效應(yīng),取它們之間版本最低的那個(gè)版本的操作行為來處理的。這會導(dǎo)致:低版本的文檔把高版本的文檔程序中的最新功能給屏蔽了,或低版本的文檔程序把高版本的文檔回退到了低版本。沒有做到各盡其用。
(4) 對協(xié)同編輯操作行為的研究[4]。
模板方法[1],是GOF中的23種設(shè)計(jì)模式中的一種模式。模板方法:在一個(gè)方法中定義一個(gè)算法的骨架,而將一些實(shí)現(xiàn)步驟延遲到子類中。模板方法使得子類可以在不改變算法結(jié)構(gòu)的情況下,重新定義算法中的某些步驟,如圖1所示:
圖1 GOF中的模板方法的類圖[1]
基于模板方法的文檔設(shè)計(jì)模式,就是在文檔應(yīng)用框架中定義一簇通用文檔程序架構(gòu)中操作行為的骨架。涉及到行為統(tǒng)一的邏輯處理,都會被放到框架中實(shí)現(xiàn),而對于不同文檔操作行為的處理,延遲到對應(yīng)文檔類中來實(shí)現(xiàn)。這樣使得單文檔操作行為和多文檔操作行為在UI層上是行為統(tǒng)一的。從而給用戶帶來一致的交互體驗(yàn)。
通用文檔程序中的操作行為難以實(shí)現(xiàn)重用和擴(kuò)展,根本原因是沒有把處理邏輯和處理程序有效分離。本文設(shè)計(jì)了一套基于模板方法的文檔設(shè)計(jì)模式,去幫助通用文檔程序的開發(fā)人員處理文檔程序的通用邏輯,規(guī)定通用文檔程序的操作行為,然后開發(fā)人員可在此基礎(chǔ)上實(shí)現(xiàn)自己處理邏輯,以此實(shí)現(xiàn)通用文檔程序架構(gòu)中操作行為的通用性。
通用文檔程序架構(gòu)中操作行為的核心算法(簡稱:通用文檔算法)是基于模板方法的文檔設(shè)計(jì)模式的一種具體實(shí)現(xiàn),但不僅限于此。
該算法包括框架層核心算法、單文檔級核心算法、多文檔級核心算法。
考慮一個(gè)提供應(yīng)用類(Application)和文檔類(Document)的應(yīng)用框架。
應(yīng)用類就是用來處理文檔管理操作的。由于通用文檔應(yīng)用程序都會進(jìn)行新建工程(NewProject)、打開工程(OpenProject)、保存工程(SaveProject)、關(guān)閉工程(CloseProject)操作,這些操作,都涉及到處理以外部形式存儲的文檔和內(nèi)存中的文檔,而其中的關(guān)鍵邏輯是文檔的序列化和反序列化。為了保證行為統(tǒng)一,這邊使用了模板方法的思路。保證在做真正具體某個(gè)操作時(shí),先處理(帶Pre的操作)一定出現(xiàn)在處理前,后處理(帶Post的操作)一定出現(xiàn)在處理之后。如果不使用通用文檔算法,人們就必須在每個(gè)子類中分別保證相互的行為統(tǒng)一。不幸的是,人們很容易忘記具體的行為順序。在你使用了通用文檔算法后,你只要在子類中實(shí)現(xiàn)要實(shí)現(xiàn)的接口,就能保證相互的行為統(tǒng)一。而且編譯器能保證你必須事先實(shí)現(xiàn)那些接口,不然程序是編譯不過的。
新建工程和打開工程都會調(diào)用關(guān)閉工程,這個(gè)也是為了保證行為統(tǒng)一。防止人們在新建工程和打開工程前忘記了關(guān)閉先前打開的工程,如圖2所示:
圖2 文檔管理類類圖(即應(yīng)用類類圖)
內(nèi)存文檔基類(簡稱文檔基類)是內(nèi)存中的文檔對象的表示,必須是個(gè)抽象類。負(fù)責(zé)具體文檔的序列化操作(新建文檔OnNew、打開文檔OnOpen、保存文檔OnSave、關(guān)閉文檔 OnClose) 、文檔的邏輯操作(剪切記錄項(xiàng) Cut、復(fù)制記錄項(xiàng) Copy、粘貼記錄項(xiàng) Paste)、文檔中某一記錄項(xiàng)的操作(新建記錄項(xiàng)NewItem、打開記錄項(xiàng)OpenItem、 保存記錄項(xiàng) SaveItem、關(guān)閉記錄項(xiàng) CloseItem)、對于文檔操作的 UI層提示操作(提示用戶是否保存當(dāng)前記錄項(xiàng)的修改AskForItemSave、提示用戶為新的記錄項(xiàng)命名AskForName) 、更新UI操作(根據(jù)記錄項(xiàng)數(shù)據(jù)更新UI上控件UpdateUI、控制控件是否可被操作EnableUI等)、文檔操作中需要的輔助操作(得到某個(gè)記錄項(xiàng)GetItem、起一個(gè)不重復(fù)的記錄項(xiàng)名稱MakeName等)等的定義或?qū)崿F(xiàn)。
如圖3所示:
圖3 文檔基類類圖
AskForItemSave、AskForName、UpdateUI、MakeName操作都使用了模板方法,對應(yīng)的單文檔子類或多文檔子類則必須要實(shí)現(xiàn) SaveItem、GetNameFromUI、ValidateName、OnUpdatUI、EnableUI操作。在內(nèi)存文檔類中為了保證單文檔和多文檔的在數(shù)據(jù)層、邏輯層和UI層的操作行為統(tǒng)一,對于文檔路徑 m_strFilePath的用途也是有不同的含義和解釋的,這些在5.2和5.3中會進(jìn)行闡述。同時(shí)為了使單文檔與多文檔的操作行為保持統(tǒng)一和方便做撤銷操作和檢測修改標(biāo)志操作,需要一個(gè)臨時(shí)的記錄項(xiàng)m_item來表示當(dāng)前操作的記錄項(xiàng)。
使用通用文檔算法構(gòu)建的具體應(yīng)用可以通過繼承應(yīng)用類和文檔類來滿足特定的需求。
單文檔類是文檔基類的一個(gè)子類。在內(nèi)存中所有記錄項(xiàng)是直接存放在單文檔對象中的,而所有記錄項(xiàng)序列化時(shí)都記錄在一個(gè)在外部形式存儲的文檔中。單文檔不需要一個(gè)記錄所有記錄項(xiàng)的索引文件。記錄項(xiàng)的索引信息和所有記錄項(xiàng)的數(shù)據(jù)信息,在內(nèi)存中可以通過一個(gè)列表的形式進(jìn)行記錄,m_items就實(shí)現(xiàn)了這個(gè)用途;在外部形式存儲的文檔中(其路徑為 m_strFilePath),則通過文檔的結(jié)構(gòu)列表和具體的數(shù)據(jù)文本信息來表示。
文檔的邏輯操作、文檔中某一記錄項(xiàng)的操作、文檔操作中需要的輔助操作中的一些操作(如 GetItem),與多文檔不同,都是對內(nèi)存對象的直接操作,不涉及對數(shù)據(jù)的序列化操作。
單文檔類的實(shí)現(xiàn),如圖4所示:
圖4 單文檔類類圖
多文檔類也是文檔基類的一個(gè)子類。在內(nèi)存中只有當(dāng)前記錄項(xiàng)是直接存放在多文檔對象中的,而所有記錄項(xiàng)序列化時(shí)都分別記錄在各自在外部形式存儲的文檔中。其實(shí)準(zhǔn)確地說沒有一次對所有記錄項(xiàng)進(jìn)行序列化的操作,序列化操作一次只對單個(gè)記錄項(xiàng)進(jìn)行。且多文檔必須要有一個(gè)記錄所有記錄項(xiàng)的索引文件(其路徑為m_strFilePath),其中記錄每一個(gè)記錄項(xiàng)的名稱和記錄項(xiàng)對應(yīng)的文件名。由于這邊為了簡化算法,記錄項(xiàng)的名稱和記錄項(xiàng)對應(yīng)的文件名我們用的是同一個(gè)。所以記錄項(xiàng)的索引信息在內(nèi)存中,可以通過一個(gè)記錄項(xiàng)的名稱列表的形式進(jìn)行記錄,m_strItemFilePaths就實(shí)現(xiàn)了這個(gè)用途;在外部形式存儲的文檔中(其文檔路徑m_strFilePath),則通過記錄名稱列表信息來表示。
在多文檔中,在OnOpen操作完成之后,在內(nèi)存中只有記錄項(xiàng)的索引信息,不會有所有記錄項(xiàng)的數(shù)據(jù)信息,其實(shí)也用不著有,這個(gè)是我們有時(shí)會選擇使用多文檔而不使用單文檔的原因所在。所以想要得到某一非當(dāng)前記錄項(xiàng)的數(shù)據(jù)時(shí),必須進(jìn)行一次序列化操作。而在單文檔中,由于所有記錄項(xiàng)的數(shù)據(jù)信息在OnOpen操作完成之后,已經(jīng)全部序列化讀入內(nèi)存,當(dāng)想要得到某一非當(dāng)前記錄項(xiàng)的數(shù)據(jù)時(shí),不用再進(jìn)行序列化操作了。
文檔的邏輯操作、文檔中某一記錄項(xiàng)的操作、文檔操作中需要的輔助操作中的一些操作(如GetItem),與單文檔不同,是對在外部形式存儲的文檔進(jìn)行操作,涉及對數(shù)據(jù)的序列化操作。但是由于多文檔類和單文檔類的基類中(文檔基類)使用了模板方法,就會給用戶帶來一致的操作體驗(yàn)。
多文檔類的實(shí)現(xiàn),如圖5所示:
圖5 多文檔類類圖
部分關(guān)鍵操作的偽代碼實(shí)現(xiàn),已經(jīng)在圖2、圖3、圖4、圖5中給出。
現(xiàn)已經(jīng)在盛大游戲《零世界》的專業(yè)版編輯器中得到運(yùn)用,且取得不錯的效果。在該編輯器中:
對于每個(gè)記錄項(xiàng)數(shù)據(jù)多而復(fù)雜的模塊,采用多文檔操作行為。如:場景模塊、資源模塊等。
對于每個(gè)記錄項(xiàng)數(shù)據(jù)少而簡單的模塊,采用單文檔操作行為。如:任務(wù)模塊、怪物模塊、主角模塊、物品模塊等。
用戶在使用編輯器時(shí),完全不會察覺各個(gè)模塊之間操作有何不同。
其實(shí)這邊給出的通用文檔算法十分通用,幾乎可以用在任何一個(gè)文檔程序中。說不定,你寫過的文檔程序就已經(jīng)部分用上了這個(gè)算法。
本文設(shè)計(jì)了通用文檔算法,對于不同應(yīng)用類型的文檔程序架構(gòu)中操作行為進(jìn)行了提煉,解決了操作行為統(tǒng)一的難題。只需要按照已定義的接口編寫對應(yīng)的實(shí)現(xiàn)即可,開發(fā)效率會有很大提高,而且具有開發(fā)簡單、可靠性高、重用性強(qiáng)、可讀性好、容易操作等優(yōu)點(diǎn)。若有新類型的文檔處理需求,可以通過添加新的單文檔或多文檔子類來實(shí)現(xiàn);若有新的操作行為需求,可以通過在文檔基類添加新的操作行為接口,并在單文檔或多文檔類中實(shí)現(xiàn)之來解決。這對于解決通用文檔程序架構(gòu)中操作行為的一致處理,有可能是一個(gè)比較合理的解決方案。
由此可見,研究通用文檔程序架構(gòu)中操作行為,尤其是針對復(fù)雜龐大的編輯器,從文檔底層的數(shù)據(jù)操作、文檔的邏輯操作、文檔的UI層操作3個(gè)層面統(tǒng)籌考慮操作行為,具有非常重要的理論與現(xiàn)實(shí)意義。
當(dāng)然通用文檔算法還有很多地方需要改進(jìn),讀者可以從以下幾個(gè)方面進(jìn)行深入研究,為文檔程序架構(gòu)中操作行為架構(gòu)帶來更好的、更全面的應(yīng)用解決方案:
(1) 針對統(tǒng)一資源管理下的(如:SVN管理下的)文檔操作行為的研究。
(2) 虛擬單文件下的單文檔和多文檔操作行為相統(tǒng)一的研究。
(3) 針對協(xié)同編輯操作行為的研究。
(4) 剪切、復(fù)制、粘貼支持一次操作多個(gè)記錄項(xiàng)。
(5) 多文檔中存放記錄項(xiàng)數(shù)據(jù)的文件名稱可以與記錄項(xiàng)名稱不同。
[1]Erich Gamma, Richard Helm, Ralph Johnson, John Lissides. Design Patterns:Elements of Reusable Object-Oriented software[C]. USA:Addison-Wesley Professional, 1994: 346-352.
[2]孫尚輝, 曹寶香, 王廷蔚. 擴(kuò)展RBAC模型在文檔管理中的應(yīng)用[J].. 計(jì)算機(jī)技術(shù)與發(fā)展, 2007, (3).
[3]劉麗偉, 鄧春健. 多文件壓縮傳輸及解壓縮的方法[J].武漢理工大學(xué)學(xué)報(bào)(交通科學(xué)與工程版), 2009, (6) .
[4]陳麗. 協(xié)同編輯系統(tǒng)中并發(fā)控制的研究與實(shí)現(xiàn).[j]網(wǎng)絡(luò)出版年期, 2009, (7).
[5]崔明煜, 劉麗蘭, 宋娜, 孫海洋. 協(xié)同設(shè)計(jì)中基于標(biāo)記文件的版本管理[J].. 機(jī)械工程師, 2007, (10).