【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(七):WTP數(shù)據(jù)模型總結(jié)和模型管理
前面已經(jīng)詳細(xì)介紹過WTP語法Document(IStructuredDocument)、WTP語義Document(IDOMDocument或ICSSDocument)和WTP Model(IStructuredModel),在本節(jié)中將從總體上再看一下對(duì)我們后續(xù)基于WTP進(jìn)行代碼定制很重要的點(diǎn),同時(shí)將補(bǔ)充最核心的一個(gè)點(diǎn):WTP中的模型管理機(jī)制。
PS:如果前面的幾節(jié)是探微的過程,那邊本節(jié)將完成知著的過程,“探微知著”^_^
【語法Document、語義Document、WTP Model】

(說明:上圖中的實(shí)線可以理解為引用關(guān)系。)

【從引用關(guān)系層面看】
1、從上圖一可以看的出來,IStructuredDocument并不引用IStrcuturedModel或者IDOMDocument(或ICSSDocument),也就是說IStructuredDocument本身并不關(guān)心IStrcuturedModel或者IDOMDocument(或ICSSDocument)的存在
2、結(jié)合上圖一和上圖二,可以看的出來IStructuredModel將IStructuredDocument和IDOMDocument(或ICSSDocument)作為其兩個(gè)組成部分。換個(gè)角度說,如果已知IStructuredModel存在的情況下,IStructuredModel可以作為三者的門面,對(duì)IStructuredModel進(jìn)行管理也就間接對(duì)IStructuredDocument和IDOMDocument(或ICSSDocument)進(jìn)行管理
3、我們解釋一下上圖一中的那條藍(lán)色虛線,我們已經(jīng)說過IStructuredDocument本身并不關(guān)心IStrcuturedModel或者IDOMDocument(或ICSSDocument)的存在,所以要想以IStructuredDocument獲取對(duì)應(yīng)的IStructuredModel,需要一個(gè)第三方的角色,來維護(hù)從IStructuredDocument到IStructuredModel的映射關(guān)系,這個(gè)角色就是后面要說的WTP提供的IModelManager。如果IStructuredDocument通過IModelManager獲取到了對(duì)應(yīng)的IStructuredModel,那么再通過IStructuredModel可以自然獲取到對(duì)應(yīng)的語義Document(IDOMDocument或者ICSSDocument)。這樣三者就完全聯(lián)系起來了^_^
我們看一下,以上的引用關(guān)系對(duì)應(yīng)的API接口是什么(需要熟練掌握):
1、WTP Model --》 語法Document
IStructuredModel.getStructuredDocument()
2、WTP Model --》 語義Document
IDOMModel.getDocument 返回的語義Document類型為IDOMDocument
ICSSModel.getDocument 返回的語義Document類型為ICSSDocument
3、語義Document --》 WTP Model
IDOMNode.getModel (IDOMDocument本身就是IDOMNode^_^)
ICSSDocument.getModel
4、語法Document --》 WTP Model
前提:對(duì)應(yīng)的IStructuredModel已經(jīng)被WTP提供的IModelManager托管了,否則是沒有意義的(前面說過,因?yàn)镮StructuredDocument并不關(guān)心IStructuredModel和語義Document是否存在)
IModelManager.getModelForEdit(IStructuredDocument)
IModelManager.getModelForRead(IStructuredDocument)
5、語法Document --》 語義Document
前提:對(duì)應(yīng)的IStructuredModel已經(jīng)被WTP提供的IModelManager托管了?。。?br /> 步驟:語法Document --》 WTP Model --》 語義Document
6、語義Document --》 語法Document
方法一:IDOMNode.getStructuredDocument
方法二:語義Document --》 WTP Model --》 語法Document
PS:通過上面的5和6也可以體會(huì)到,WTP Model存在的情況下,完全可以在語法Document和語義Document之前起到一個(gè)橋梁的作用
【從依賴關(guān)系層面看】
1、通過上圖二IStructuredModel的構(gòu)造過程就可以看的出來,WTP Model和語義Document(IDOMDocument或者ICSSDocument)都是以IStructuredDocument為基礎(chǔ),也就是說依賴于它
2、語法Document(IStructuredDocument)不需要關(guān)心其他兩者是否存在
3、語義Document(IDOMDocument或者ICSSDocument)依賴于語法Document(IStructuredDocument)
4、一個(gè)完整的WTP Model必須有對(duì)應(yīng)的語法Document和語義Document,從這個(gè)意義上將,可以理解為WTP Model需要依賴語法Document和語義Document。
由上面四點(diǎn),我們可以簡要的畫一個(gè)三者之間的依賴關(guān)系圖:

(依賴關(guān)系圖:上圖中的實(shí)線可以理解為依賴關(guān)系)
【從動(dòng)態(tài)變化角度看(簡要了解一下就可以了^_^)】
上面我們講了這么多三者之間的關(guān)系,好像總感覺是從靜態(tài)的角度出發(fā)的,那么如果三者中的一者發(fā)生變化了,三者直接又會(huì)又什么樣的互動(dòng)呢?
1、WTP Model作為變化源,變化情況如下:
IStructuredModel引發(fā)的變化,通常情況下就是調(diào)用了IStructuredModel的reload和reinit的操作。這個(gè)操作會(huì)修改其持有的IStructuredDocument,引起IStructuredDocument改變事件。IStructuredModel本身又是一個(gè)IStructuredDocumentListener,所以會(huì)處理這種變化,在變化的處理過程中包含了修改其持有的語義Document。大致過程示意圖如下:

2、IStructuredDocument作為變化源,變化情況如下(這將是我們最常見的情況):

3、IDOMDocument作為變化源,變化情況如下:

說明:語義Document(IDOMDoucment或者ICSSDocument)持有一個(gè)IStructuredModel的引用,所以才有了上圖中的回調(diào)??梢钥吹某鰜碚Z義Document(IDOMDoucment或者ICSSDocument)并沒有提供對(duì)應(yīng)的listener接口,采用的是直接回調(diào)的辦法。
上面三個(gè)動(dòng)態(tài)變化需要經(jīng)常使用這幾個(gè)WTP數(shù)據(jù)模型才能有比較深的印象,考慮到確實(shí)有點(diǎn)繁瑣,所以就不做代碼分析了,這里留個(gè)大概印象就可以了。
提醒:IStructuredModel對(duì)應(yīng)的三個(gè)子類(AbstractStructuredModel、DOMModelImpl和CSSModelImpl)分別都有IStructuredDocumentListener實(shí)現(xiàn),有時(shí)間可以看一下這些實(shí)現(xiàn)之間的差別,對(duì)加深WTP數(shù)據(jù)模型的認(rèn)識(shí)會(huì)有幫助。
【IModelManager!!!】
( IModelManager:org.eclipse.wst.sse.core.internal.provisional.IModelManager)
【IModelManager為什么存在?】
我們先來考慮幾個(gè)問題:
1、 無論是語法Document還是語義Document的實(shí)例化過程(可不是new一個(gè)實(shí)例那么簡單^_^)都十分繁瑣,這個(gè)實(shí)例化的活是留給客戶調(diào)用端還是提供一個(gè)負(fù)責(zé)實(shí)例化的中間角色(客戶端通過調(diào)用這個(gè)中間角色來完成實(shí)例化的工作)?
答案:肯定盡量選擇后者。將客戶端和對(duì)象的繁瑣實(shí)例化過程進(jìn)行解耦,是一個(gè)我們應(yīng)該盡量遵循的規(guī)則。這個(gè)封裝了實(shí)例化過程的中間角色就是IModelLoader:org.eclipse.wst.sse.core.internal.provisional.IModelLoader)和IDocumentLoader(org.eclipse.wst.sse.core.internal.document.IDocumentLoader),我可以寬泛地將這個(gè)中間角色理解為工廠,而且實(shí)例化過程可能有變化,所以這個(gè)工廠不能是一個(gè)簡單靜態(tài)工廠,而應(yīng)該是一個(gè)工廠方法應(yīng)用(為什么不是抽象工廠,因?yàn)椴皇莿?chuàng)建相關(guān)的系列實(shí)例,也談不上什么幾個(gè)產(chǎn)品系列^_^)。
2、一個(gè)WTP Model同時(shí)持有一個(gè)重量級(jí)的語法Document和語義Document,這個(gè)兩個(gè)Document無論是在時(shí)間占用(解析過程十分耗時(shí)),還是在內(nèi)存占用方法都比較客觀。那么,如果我們對(duì)WTP Model實(shí)例進(jìn)行緩存管理,在內(nèi)存占用可接受的情況下可以大大解決時(shí)間占用的性能瓶頸問題,不挺好嗎?
答案:是挺好的^_^。 IModelManager一部分任務(wù)就是干這個(gè)事情。注意這邊的緩存管理可不簡單就是將對(duì)象存儲(chǔ)下來這么簡單,也需要提供用于更新被緩存對(duì)象的方法。
3、如果提供能夠?qū)⑸厦鎯蓚€(gè)角色組合在一起,對(duì)一般用戶而且使用起來是不是會(huì)更方便一點(diǎn)?
答案:是的。但是有點(diǎn)不太優(yōu)雅,職責(zé)有點(diǎn)混淆,不過問題不是很丑陋^_^。
回答完以上三個(gè)問題之后,我們可以猜測出來IModelManager承擔(dān)的兩個(gè)個(gè)核心任務(wù):
1、創(chuàng)建型工廠(IDocumentLoader、IModelLoader)的門面,提供創(chuàng)建接口
2、緩存管理:包含緩存實(shí)例的存儲(chǔ)管理和更新維護(hù)等任務(wù)。
【IModelManager創(chuàng)建職責(zé)】

說明:
1、上圖中包含了創(chuàng)建IStructuredModel、IStructuredDocument的方法,并沒有提供創(chuàng)建語義Document(IDOMDocument或者ICSSDocument)的方法。為什么?我們前面說過IStructuredDocument可以并不關(guān)心IStructuredModel或者語義Document是否存在,所以可以允許獨(dú)立創(chuàng)建;而語法Document和語義Document是IStructuredModel的兩個(gè)必然組成部分,所以提供了IStructuredModel的創(chuàng)建方法,就間接提供了語義Document的創(chuàng)建服務(wù)。
2、以上創(chuàng)建方法返回的實(shí)例都是未經(jīng)托管的,每次都會(huì)創(chuàng)建一個(gè)新的實(shí)例。千萬不要誤認(rèn)為IModelManager提供的創(chuàng)建方法返回的實(shí)例都是緩存的?。?!^_^ 前面說過,WTP提供的語法Document和語義Document在時(shí)間占用和內(nèi)存占用方面都是比較可觀的,小心?。。。。。。。。。。。。?!
3、注意createStructuredDocumentFor(IFile iFile)和createNewStructuredDocumentFor(IFile iFile)兩個(gè)方法的正確用法,前者基于iFile存在,后者基于iFile不存在。
【IModelManager管理職責(zé)】


說明:
1、getModelFor*不假定模型已經(jīng)被托管,沒有對(duì)應(yīng)的模型情況下會(huì)創(chuàng)建一個(gè)新的被托管的實(shí)例(但是不能以IDocument為參數(shù));getExistingModelFor*假設(shè)有對(duì)應(yīng)的被托管模型存在于IModelManager種,否則返回null,不創(chuàng)建新的被托管實(shí)例。
2、getModelFor*和getExistingModelFor*都涉及到引用計(jì)數(shù)的概念,每次調(diào)用都會(huì)增加read或者editor計(jì)數(shù),使用完畢之后應(yīng)該調(diào)用IStructuredModel.releaseFromEdit或者IStructuredModel.releaseFromRead。
3、IModelManager并沒有提供IStructuredDocument的獲取接口,因?yàn)镮ModelManager管理的目標(biāo)只是IStructuredModel。IStructuredDocument雖然可以脫離IStructuredModel獨(dú)立存在,但是IModelManager不提供管理。
4、使用getModelFor*(IDocument)和getExistingModelFor*(IDocument)的前提必須是有對(duì)應(yīng)的IStructuredModel被托管了。示例代碼:
PS:IModelManager的其他操作就不一一列舉了,具體可以看一下對(duì)應(yīng)代碼。IModelManager的獲取方式上面代碼中已經(jīng)體現(xiàn):org.eclipse.wst.sse.core.StructuredModelManager中提供了getModelManager操作來獲取IModelManager實(shí)例。
【使用WTP IModelManager一定要注意的地方】
1、根據(jù)你的模型是否需要被緩存托管,判斷該調(diào)用什么方法。如果不需要被托管的模型卻被緩存托管了,則會(huì)大大增加內(nèi)存占用。
2、注意維護(hù)引用計(jì)數(shù)平衡
【語法Region VS 語義Region】
語法Document(IStructuredDocument)提供了語法Region(ITextRegion)的概念,語義Document(IDOMDocument或者ICSSDocument)對(duì)應(yīng)的是語義Region(IndexedRegion、IDOMNode、ICSSNode),那我們現(xiàn)在來看一下它們之間的區(qū)別和聯(lián)系。
【區(qū)別】

顯而易見,語法Region(ITextRegion)是按照語法進(jìn)行劃分的,既然是structured region,那么劃分時(shí)候一個(gè)重要的判斷依據(jù)就是特定的文本是否是結(jié)構(gòu)化的。IStructuredDocumentRegion代表的就是一個(gè)結(jié)構(gòu)化的region,里面會(huì)含有一系列的葉子節(jié)點(diǎn)的text region。IStructuredDocumentRegion之間并不會(huì)呈現(xiàn)父子關(guān)系,例如父子標(biāo)簽之間是獨(dú)立的IStructuredDocumentRegion,因?yàn)檫@個(gè)父子是從語義層面才有意思。

語義Region(IndexedRegion、IDOMNode、ICSSNode)則是按照語義進(jìn)行劃分的,體現(xiàn)的語義層面的包含關(guān)系。例如,子標(biāo)簽會(huì)作為一個(gè)child node(IDOMElement)存在于父標(biāo)簽中(同樣是一個(gè)IDOMElement);再例如一個(gè)IDOMAttr表示一個(gè)屬性,如果切換到語法region視角,則對(duì)應(yīng)于三個(gè)ITextRegion:AttributeNameRegion、AttributeEqualsRegion、AttributeValueRegion。
一句話,根據(jù)應(yīng)用場景的不同你可以選擇借助語法region進(jìn)行分析或者借助語義region進(jìn)行分析。例如:如果要判斷一個(gè)標(biāo)簽是否在其特定父標(biāo)簽中,則用語義region進(jìn)行分析會(huì)方便很多^_^。
【聯(lián)系】
那我們?nèi)绾螌⒄Z法Region和語義Region比較方便的聯(lián)系起來呢?
答案:offset(位置信息)?。。?br />
基于語法Document構(gòu)建語義Document,說白了就是把語法region列表重新組織為語義region列表,語法region本身就持有位置信息,語義region會(huì)持有對(duì)應(yīng)的語法region,所以語義region本身也可以提供位置信息了。前面曾經(jīng)說過,所有的語義region都是IndexedRegion接口的實(shí)現(xiàn),IndexedRegion定義的核心操作也就是獲取位置信息的。
根據(jù)offset信息可以定位到對(duì)應(yīng)的語法region或者語義region,涉及到的方法前面已經(jīng)在講述相關(guān)接口的時(shí)候講述過,這邊就不再重復(fù)了。(這些東西用用就熟悉了^_^)
IndexedRegion IStructuredModel.getIndexedRegion(int offset)
IStructuredDocumentRegion IStructuredDocument.getRegionAtCharacterOffset(int offset)
PS:如果你持有的是一個(gè)語義region,則可以直接根據(jù)語義region去獲取其引用的語法region。
【后記】
到目前,WTP數(shù)據(jù)模型相關(guān)的東西真的告一段落了,其實(shí)這并不是WTP數(shù)據(jù)模型的全部,后門我們?cè)诙x具體功能的時(shí)候會(huì)順便再講一下其他的數(shù)據(jù)模型,我們可以把那些模型稱之為元數(shù)據(jù)模型,很多其實(shí)就是再IStructuredModel基礎(chǔ)之上再提供額外的描述信息。
PS:如果前面的幾節(jié)是探微的過程,那邊本節(jié)將完成知著的過程,“探微知著”^_^
【語法Document、語義Document、WTP Model】
(說明:上圖中的實(shí)線可以理解為引用關(guān)系。)
【從引用關(guān)系層面看】
1、從上圖一可以看的出來,IStructuredDocument并不引用IStrcuturedModel或者IDOMDocument(或ICSSDocument),也就是說IStructuredDocument本身并不關(guān)心IStrcuturedModel或者IDOMDocument(或ICSSDocument)的存在
2、結(jié)合上圖一和上圖二,可以看的出來IStructuredModel將IStructuredDocument和IDOMDocument(或ICSSDocument)作為其兩個(gè)組成部分。換個(gè)角度說,如果已知IStructuredModel存在的情況下,IStructuredModel可以作為三者的門面,對(duì)IStructuredModel進(jìn)行管理也就間接對(duì)IStructuredDocument和IDOMDocument(或ICSSDocument)進(jìn)行管理
3、我們解釋一下上圖一中的那條藍(lán)色虛線,我們已經(jīng)說過IStructuredDocument本身并不關(guān)心IStrcuturedModel或者IDOMDocument(或ICSSDocument)的存在,所以要想以IStructuredDocument獲取對(duì)應(yīng)的IStructuredModel,需要一個(gè)第三方的角色,來維護(hù)從IStructuredDocument到IStructuredModel的映射關(guān)系,這個(gè)角色就是后面要說的WTP提供的IModelManager。如果IStructuredDocument通過IModelManager獲取到了對(duì)應(yīng)的IStructuredModel,那么再通過IStructuredModel可以自然獲取到對(duì)應(yīng)的語義Document(IDOMDocument或者ICSSDocument)。這樣三者就完全聯(lián)系起來了^_^
我們看一下,以上的引用關(guān)系對(duì)應(yīng)的API接口是什么(需要熟練掌握):
1、WTP Model --》 語法Document
IStructuredModel.getStructuredDocument()
IDOMModel.getDocument 返回的語義Document類型為IDOMDocument
ICSSModel.getDocument 返回的語義Document類型為ICSSDocument
3、語義Document --》 WTP Model
IDOMNode.getModel (IDOMDocument本身就是IDOMNode^_^)
4、語法Document --》 WTP Model
前提:對(duì)應(yīng)的IStructuredModel已經(jīng)被WTP提供的IModelManager托管了,否則是沒有意義的(前面說過,因?yàn)镮StructuredDocument并不關(guān)心IStructuredModel和語義Document是否存在)
IModelManager.getModelForEdit(IStructuredDocument)
IModelManager.getModelForRead(IStructuredDocument)
5、語法Document --》 語義Document
前提:對(duì)應(yīng)的IStructuredModel已經(jīng)被WTP提供的IModelManager托管了?。。?br /> 步驟:語法Document --》 WTP Model --》 語義Document
6、語義Document --》 語法Document
方法一:IDOMNode.getStructuredDocument
方法二:語義Document --》 WTP Model --》 語法Document
PS:通過上面的5和6也可以體會(huì)到,WTP Model存在的情況下,完全可以在語法Document和語義Document之前起到一個(gè)橋梁的作用
【從依賴關(guān)系層面看】
1、通過上圖二IStructuredModel的構(gòu)造過程就可以看的出來,WTP Model和語義Document(IDOMDocument或者ICSSDocument)都是以IStructuredDocument為基礎(chǔ),也就是說依賴于它
2、語法Document(IStructuredDocument)不需要關(guān)心其他兩者是否存在
3、語義Document(IDOMDocument或者ICSSDocument)依賴于語法Document(IStructuredDocument)
4、一個(gè)完整的WTP Model必須有對(duì)應(yīng)的語法Document和語義Document,從這個(gè)意義上將,可以理解為WTP Model需要依賴語法Document和語義Document。
由上面四點(diǎn),我們可以簡要的畫一個(gè)三者之間的依賴關(guān)系圖:
(依賴關(guān)系圖:上圖中的實(shí)線可以理解為依賴關(guān)系)
【從動(dòng)態(tài)變化角度看(簡要了解一下就可以了^_^)】
上面我們講了這么多三者之間的關(guān)系,好像總感覺是從靜態(tài)的角度出發(fā)的,那么如果三者中的一者發(fā)生變化了,三者直接又會(huì)又什么樣的互動(dòng)呢?
1、WTP Model作為變化源,變化情況如下:
IStructuredModel引發(fā)的變化,通常情況下就是調(diào)用了IStructuredModel的reload和reinit的操作。這個(gè)操作會(huì)修改其持有的IStructuredDocument,引起IStructuredDocument改變事件。IStructuredModel本身又是一個(gè)IStructuredDocumentListener,所以會(huì)處理這種變化,在變化的處理過程中包含了修改其持有的語義Document。大致過程示意圖如下:
2、IStructuredDocument作為變化源,變化情況如下(這將是我們最常見的情況):
3、IDOMDocument作為變化源,變化情況如下:
//獲取語義Document
IDOMDocument domDocument = ((IDOMModel)structuredModel).getDocument();
//修改語義Document,例如刪除其第一個(gè)節(jié)點(diǎn)
Node node = domDocument.getChildNodes().item(0);
domDocument.removeChild(node);
以上代碼會(huì)發(fā)生如下事情:首先DOM Document被修改,然后會(huì)回調(diào)DOMModelImpl中對(duì)應(yīng)的更新方法(例如DOMModelImpl.childReplaced),然后會(huì)調(diào)用一個(gè)XMLModelUpdater的角色,在這個(gè)XMLModelUpdater會(huì)去更新IStructuredDocument(replace text操作),這進(jìn)而會(huì)引發(fā)IStructuredDocument改變事件,會(huì)進(jìn)而進(jìn)入上面已經(jīng)闡述過的循環(huán)。大致示意圖如下:IDOMDocument domDocument = ((IDOMModel)structuredModel).getDocument();
//修改語義Document,例如刪除其第一個(gè)節(jié)點(diǎn)
Node node = domDocument.getChildNodes().item(0);
domDocument.removeChild(node);
說明:語義Document(IDOMDoucment或者ICSSDocument)持有一個(gè)IStructuredModel的引用,所以才有了上圖中的回調(diào)??梢钥吹某鰜碚Z義Document(IDOMDoucment或者ICSSDocument)并沒有提供對(duì)應(yīng)的listener接口,采用的是直接回調(diào)的辦法。
上面三個(gè)動(dòng)態(tài)變化需要經(jīng)常使用這幾個(gè)WTP數(shù)據(jù)模型才能有比較深的印象,考慮到確實(shí)有點(diǎn)繁瑣,所以就不做代碼分析了,這里留個(gè)大概印象就可以了。
提醒:IStructuredModel對(duì)應(yīng)的三個(gè)子類(AbstractStructuredModel、DOMModelImpl和CSSModelImpl)分別都有IStructuredDocumentListener實(shí)現(xiàn),有時(shí)間可以看一下這些實(shí)現(xiàn)之間的差別,對(duì)加深WTP數(shù)據(jù)模型的認(rèn)識(shí)會(huì)有幫助。
【IModelManager!!!】
( IModelManager:org.eclipse.wst.sse.core.internal.provisional.IModelManager)
【IModelManager為什么存在?】
我們先來考慮幾個(gè)問題:
1、 無論是語法Document還是語義Document的實(shí)例化過程(可不是new一個(gè)實(shí)例那么簡單^_^)都十分繁瑣,這個(gè)實(shí)例化的活是留給客戶調(diào)用端還是提供一個(gè)負(fù)責(zé)實(shí)例化的中間角色(客戶端通過調(diào)用這個(gè)中間角色來完成實(shí)例化的工作)?
答案:肯定盡量選擇后者。將客戶端和對(duì)象的繁瑣實(shí)例化過程進(jìn)行解耦,是一個(gè)我們應(yīng)該盡量遵循的規(guī)則。這個(gè)封裝了實(shí)例化過程的中間角色就是IModelLoader:org.eclipse.wst.sse.core.internal.provisional.IModelLoader)和IDocumentLoader(org.eclipse.wst.sse.core.internal.document.IDocumentLoader),我可以寬泛地將這個(gè)中間角色理解為工廠,而且實(shí)例化過程可能有變化,所以這個(gè)工廠不能是一個(gè)簡單靜態(tài)工廠,而應(yīng)該是一個(gè)工廠方法應(yīng)用(為什么不是抽象工廠,因?yàn)椴皇莿?chuàng)建相關(guān)的系列實(shí)例,也談不上什么幾個(gè)產(chǎn)品系列^_^)。
2、一個(gè)WTP Model同時(shí)持有一個(gè)重量級(jí)的語法Document和語義Document,這個(gè)兩個(gè)Document無論是在時(shí)間占用(解析過程十分耗時(shí)),還是在內(nèi)存占用方法都比較客觀。那么,如果我們對(duì)WTP Model實(shí)例進(jìn)行緩存管理,在內(nèi)存占用可接受的情況下可以大大解決時(shí)間占用的性能瓶頸問題,不挺好嗎?
答案:是挺好的^_^。 IModelManager一部分任務(wù)就是干這個(gè)事情。注意這邊的緩存管理可不簡單就是將對(duì)象存儲(chǔ)下來這么簡單,也需要提供用于更新被緩存對(duì)象的方法。
3、如果提供能夠?qū)⑸厦鎯蓚€(gè)角色組合在一起,對(duì)一般用戶而且使用起來是不是會(huì)更方便一點(diǎn)?
答案:是的。但是有點(diǎn)不太優(yōu)雅,職責(zé)有點(diǎn)混淆,不過問題不是很丑陋^_^。
回答完以上三個(gè)問題之后,我們可以猜測出來IModelManager承擔(dān)的兩個(gè)個(gè)核心任務(wù):
1、創(chuàng)建型工廠(IDocumentLoader、IModelLoader)的門面,提供創(chuàng)建接口
2、緩存管理:包含緩存實(shí)例的存儲(chǔ)管理和更新維護(hù)等任務(wù)。
【IModelManager創(chuàng)建職責(zé)】
說明:
1、上圖中包含了創(chuàng)建IStructuredModel、IStructuredDocument的方法,并沒有提供創(chuàng)建語義Document(IDOMDocument或者ICSSDocument)的方法。為什么?我們前面說過IStructuredDocument可以并不關(guān)心IStructuredModel或者語義Document是否存在,所以可以允許獨(dú)立創(chuàng)建;而語法Document和語義Document是IStructuredModel的兩個(gè)必然組成部分,所以提供了IStructuredModel的創(chuàng)建方法,就間接提供了語義Document的創(chuàng)建服務(wù)。
2、以上創(chuàng)建方法返回的實(shí)例都是未經(jīng)托管的,每次都會(huì)創(chuàng)建一個(gè)新的實(shí)例。千萬不要誤認(rèn)為IModelManager提供的創(chuàng)建方法返回的實(shí)例都是緩存的?。?!^_^ 前面說過,WTP提供的語法Document和語義Document在時(shí)間占用和內(nèi)存占用方面都是比較可觀的,小心?。。。。。。。。。。。。?!
3、注意createStructuredDocumentFor(IFile iFile)和createNewStructuredDocumentFor(IFile iFile)兩個(gè)方法的正確用法,前者基于iFile存在,后者基于iFile不存在。
【IModelManager管理職責(zé)】
說明:
1、getModelFor*不假定模型已經(jīng)被托管,沒有對(duì)應(yīng)的模型情況下會(huì)創(chuàng)建一個(gè)新的被托管的實(shí)例(但是不能以IDocument為參數(shù));getExistingModelFor*假設(shè)有對(duì)應(yīng)的被托管模型存在于IModelManager種,否則返回null,不創(chuàng)建新的被托管實(shí)例。
2、getModelFor*和getExistingModelFor*都涉及到引用計(jì)數(shù)的概念,每次調(diào)用都會(huì)增加read或者editor計(jì)數(shù),使用完畢之后應(yīng)該調(diào)用IStructuredModel.releaseFromEdit或者IStructuredModel.releaseFromRead。
3、IModelManager并沒有提供IStructuredDocument的獲取接口,因?yàn)镮ModelManager管理的目標(biāo)只是IStructuredModel。IStructuredDocument雖然可以脫離IStructuredModel獨(dú)立存在,但是IModelManager不提供管理。
4、使用getModelFor*(IDocument)和getExistingModelFor*(IDocument)的前提必須是有對(duì)應(yīng)的IStructuredModel被托管了。示例代碼:
try {
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("/project/WebContent/Test2.jsp"));
IStructuredDocument document = StructuredModelManager.getModelManager().createStructuredDocumentFor(file);
Object model1 = StructuredModelManager.getModelManager().getModelForRead(document);
Object model2 = StructuredModelManager.getModelManager().getExistingModelForEdit(document);
} catch (Exception e) {
e.printStackTrace();
}
如果上面代碼種的file代表的資源沒有對(duì)應(yīng)的IStructuredModel被托管,則model1和model2的獲取都會(huì)引發(fā)異常。如果調(diào)用getModelFor*(IFile)或 getExistingModelFor*(IFile)則不會(huì)出現(xiàn)問題。IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("/project/WebContent/Test2.jsp"));
IStructuredDocument document = StructuredModelManager.getModelManager().createStructuredDocumentFor(file);
Object model1 = StructuredModelManager.getModelManager().getModelForRead(document);
Object model2 = StructuredModelManager.getModelManager().getExistingModelForEdit(document);
} catch (Exception e) {
e.printStackTrace();
}
PS:IModelManager的其他操作就不一一列舉了,具體可以看一下對(duì)應(yīng)代碼。IModelManager的獲取方式上面代碼中已經(jīng)體現(xiàn):org.eclipse.wst.sse.core.StructuredModelManager中提供了getModelManager操作來獲取IModelManager實(shí)例。
【使用WTP IModelManager一定要注意的地方】
1、根據(jù)你的模型是否需要被緩存托管,判斷該調(diào)用什么方法。如果不需要被托管的模型卻被緩存托管了,則會(huì)大大增加內(nèi)存占用。
2、注意維護(hù)引用計(jì)數(shù)平衡
【語法Region VS 語義Region】
語法Document(IStructuredDocument)提供了語法Region(ITextRegion)的概念,語義Document(IDOMDocument或者ICSSDocument)對(duì)應(yīng)的是語義Region(IndexedRegion、IDOMNode、ICSSNode),那我們現(xiàn)在來看一下它們之間的區(qū)別和聯(lián)系。
【區(qū)別】
顯而易見,語法Region(ITextRegion)是按照語法進(jìn)行劃分的,既然是structured region,那么劃分時(shí)候一個(gè)重要的判斷依據(jù)就是特定的文本是否是結(jié)構(gòu)化的。IStructuredDocumentRegion代表的就是一個(gè)結(jié)構(gòu)化的region,里面會(huì)含有一系列的葉子節(jié)點(diǎn)的text region。IStructuredDocumentRegion之間并不會(huì)呈現(xiàn)父子關(guān)系,例如父子標(biāo)簽之間是獨(dú)立的IStructuredDocumentRegion,因?yàn)檫@個(gè)父子是從語義層面才有意思。
語義Region(IndexedRegion、IDOMNode、ICSSNode)則是按照語義進(jìn)行劃分的,體現(xiàn)的語義層面的包含關(guān)系。例如,子標(biāo)簽會(huì)作為一個(gè)child node(IDOMElement)存在于父標(biāo)簽中(同樣是一個(gè)IDOMElement);再例如一個(gè)IDOMAttr表示一個(gè)屬性,如果切換到語法region視角,則對(duì)應(yīng)于三個(gè)ITextRegion:AttributeNameRegion、AttributeEqualsRegion、AttributeValueRegion。
一句話,根據(jù)應(yīng)用場景的不同你可以選擇借助語法region進(jìn)行分析或者借助語義region進(jìn)行分析。例如:如果要判斷一個(gè)標(biāo)簽是否在其特定父標(biāo)簽中,則用語義region進(jìn)行分析會(huì)方便很多^_^。
【聯(lián)系】
那我們?nèi)绾螌⒄Z法Region和語義Region比較方便的聯(lián)系起來呢?
答案:offset(位置信息)?。。?br />
基于語法Document構(gòu)建語義Document,說白了就是把語法region列表重新組織為語義region列表,語法region本身就持有位置信息,語義region會(huì)持有對(duì)應(yīng)的語法region,所以語義region本身也可以提供位置信息了。前面曾經(jīng)說過,所有的語義region都是IndexedRegion接口的實(shí)現(xiàn),IndexedRegion定義的核心操作也就是獲取位置信息的。
根據(jù)offset信息可以定位到對(duì)應(yīng)的語法region或者語義region,涉及到的方法前面已經(jīng)在講述相關(guān)接口的時(shí)候講述過,這邊就不再重復(fù)了。(這些東西用用就熟悉了^_^)
IndexedRegion IStructuredModel.getIndexedRegion(int offset)
IStructuredDocumentRegion IStructuredDocument.getRegionAtCharacterOffset(int offset)
PS:如果你持有的是一個(gè)語義region,則可以直接根據(jù)語義region去獲取其引用的語法region。
【后記】
到目前,WTP數(shù)據(jù)模型相關(guān)的東西真的告一段落了,其實(shí)這并不是WTP數(shù)據(jù)模型的全部,后門我們?cè)诙x具體功能的時(shí)候會(huì)順便再講一下其他的數(shù)據(jù)模型,我們可以把那些模型稱之為元數(shù)據(jù)模型,很多其實(shí)就是再IStructuredModel基礎(chǔ)之上再提供額外的描述信息。
本博客中的所有文章、隨筆除了標(biāo)題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請(qǐng)注明出處,謝謝!
posted on 2008-09-18 17:57 zhuxing 閱讀(2194) 評(píng)論(2) 編輯 收藏 所屬分類: Eclipse Plug-in & OSGI 、WTP(Web Tools Platform)