




免費(fèi)預(yù)覽已結(jié)束,剩余64頁(yè)可下載查看
下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Visual Studio DSL 入門 1 什么是特定領(lǐng)域開發(fā)和DSL 特定領(lǐng)域開發(fā)是用來(lái)解決重復(fù)發(fā)生的問題的方法,針對(duì)每次發(fā)生的問題,通過進(jìn)行總結(jié)和分析,他們之間相同的方面可以一次性的解決而經(jīng)常變化的方面,可以采用一種特殊的語(yǔ)言表達(dá)針對(duì)這個(gè)特殊語(yǔ)言,我們可以建立模型或者表達(dá)式,然后插入到固定部分 對(duì)于我們軟件行業(yè)的解決方案來(lái)說,固定部分一般采用傳統(tǒng)的設(shè)計(jì)和實(shí)現(xiàn)方式,可以為框架,平臺(tái),解釋器或者編程接口提供可擴(kuò)展性,具有高度的抽象性和可復(fù)用性而特定領(lǐng)域語(yǔ)言專門用來(lái)創(chuàng)建變化的部分,從而使整個(gè)解決方案可具有可應(yīng)用性 特定領(lǐng)域語(yǔ)言(DSL,Domain Specific Language)是一種特別用來(lái)描述某一專業(yè)領(lǐng)域內(nèi)涵的描述語(yǔ)言,其實(shí)它并不陌生, HTML ,SQL都算的上是DSL的例子 幾種其它DSL MPS /mps/ JetBrains公司的DSL工具,通過這個(gè)平臺(tái)可以直接定義規(guī)則,生成代碼 MetaEdit+ / 圖形化的DSL工具 Oslo /zh-cn/data/ee460940(en-us).aspx 微軟新推出的圖形化DSL語(yǔ)言,但是Oslo和我們要介紹的DSL Toolkit還是有些區(qū)別的,這里有一些介紹/keith_short/archive/2008/11/06/oslo-and-the-dsl-toolkit.aspx .Oslo由 “M語(yǔ)言,工具Quadrant,關(guān)系存儲(chǔ)組成 GMF,EMF /modeling/gmf/ 使用 Eclipse Modeling Framework (EMF) 和 Graphical Modeling Framework (GMF) 技術(shù)來(lái)為領(lǐng)域特定語(yǔ)言(DSL)產(chǎn)生領(lǐng)域特定建模(DSM)輔助工具 什么是Visual Studio DSL Vistual Studio DSL 工具,是微軟針對(duì)特定領(lǐng)域開發(fā)而專門設(shè)計(jì)的.包含在Vistual Studio SDK中(vs 2010中將是單獨(dú)安裝),允許開發(fā)人員自行設(shè)計(jì)專屬的圖形化工具,它內(nèi)置了模型的相關(guān)支持,以及模型與圖形之間的支持,還包括對(duì)模型的驗(yàn)證,規(guī)則,事務(wù)的支持,同時(shí)還允許開發(fā)人員在結(jié)合VS.NET的一些擴(kuò)展VSX一同使用比如工具條,菜單等可以將模型與T4一同使用,從而生成目標(biāo)代碼Vs.Net現(xiàn)在的類設(shè)計(jì)器,分布式系統(tǒng)設(shè)計(jì)器(Distributed System Designer),LinqToSql設(shè)計(jì)器,EntityFramework設(shè)計(jì)器都是基于VS.NET DSL開發(fā)的,VS 2010新增了UML Modeling Project,終于提供了對(duì)類圖,時(shí)序圖,用例圖等的支持,這也是基于Vs.NET DSL來(lái)實(shí)現(xiàn)的為什么要使用DSL工具 上面介紹了幾種DSL工具,但是我們?yōu)槭裁匆褂盟?它又能給我們帶來(lái)什么呢? 很關(guān)鍵的一點(diǎn),DSL和UML不同,是用來(lái)解決問題的,而不是描述問題.如果你正在你的工作和解決方案中重復(fù)編寫著相同或者相似的代碼,而且這些重復(fù)的代碼能夠單獨(dú)出來(lái)采用生成的方式,那么你就可以考慮結(jié)合DSL工具來(lái)生成這些代碼. 可能有人會(huì)說,那這和使用現(xiàn)有的這些基于數(shù)據(jù)庫(kù)的代碼生成工具(Codesmith,李天平的codematic等)又有何不同呢?DSL是站在領(lǐng)域?qū)<业母叨?,而非軟件開發(fā)專家來(lái)開始解決問題,如果需要對(duì)數(shù)據(jù)庫(kù)進(jìn)行設(shè)計(jì),然后再生成代碼Coding,那么你這個(gè)工具只能說是開發(fā)人員的一個(gè)輔助工具,只是面對(duì)實(shí)際開發(fā)人員,而這在大型的軟件系統(tǒng)當(dāng)中會(huì)有些力不從心 采用DSL的開發(fā)過程定制 1.找出問題的固定部分,并把這些固定固定部分放在通用架構(gòu)或平臺(tái)中通用的部分基本上都是我們根據(jù)長(zhǎng)期的經(jīng)驗(yàn)和積累抽象出來(lái)固定的比如我們使用的Enterprise Library中已經(jīng)將數(shù)據(jù)訪問操作,日志操作,驗(yàn)證緩存等封裝起來(lái)提供調(diào)用 2.識(shí)別可變性和發(fā)現(xiàn)DSL. 找出其中變化的部分,并設(shè)計(jì)DSL, 通過DSL的表達(dá)式或模型提供給問題一個(gè)解決方案. 在使用Enterprise Library過程中,你發(fā)現(xiàn)其中大部分的變化的部分其實(shí)也相對(duì)固定,他們還是基于你的模型,基于你的實(shí)體模型,服務(wù)模型,如果把這些元數(shù)據(jù)抽象出來(lái),通過DSL來(lái)實(shí)現(xiàn)這些元數(shù)據(jù)的配置,那么就可以把這些部分直接生成到你的目標(biāo)解決方案中 優(yōu)勢(shì) 1.大幅度的提高生產(chǎn)率. 生成代碼可比人工復(fù)制粘貼快多了。 2.使系統(tǒng)的規(guī)范性更強(qiáng). 每個(gè)開發(fā)人員對(duì)某一個(gè)功能的都會(huì)有不同的實(shí)現(xiàn)方式,采用DSL設(shè)計(jì)模型,結(jié)合代碼生成能夠使功能的實(shí)現(xiàn)相對(duì)固定. 3.降低了犯錯(cuò)的機(jī)會(huì). 4.使非開發(fā)人員,那些顧問和售前,也能夠直接了解模型。使開發(fā)過程提前,甚至顧問的調(diào)研需求時(shí),就可以使用工具和客戶溝通,抽象需求,從而提供給二次開發(fā)人員使用. 5.能夠在較高的抽象層次對(duì)解決方案進(jìn)行驗(yàn)證,過早的發(fā)現(xiàn)問題. 6.可以基于同一個(gè)模型配置不同的技術(shù)實(shí)現(xiàn)過程.降低技術(shù)難度和工作量。比如上次介紹的Sculpture,就可以針對(duì)不同的層次,提供不同的技術(shù)選擇。針對(duì)同一個(gè)模型,我們可以選擇使用Entity Framework或者NHibernate。UI層可以選擇A MVC,Sliverlight,WPF等不同的實(shí)現(xiàn)方式. 7.DSL不局限于生成我們的技術(shù)方案,還可以用來(lái)生成構(gòu)建腳本,文檔,計(jì)劃等。 8.使解決方案進(jìn)行技術(shù)轉(zhuǎn)移變得相對(duì)容易,通過修改生成器或解釋器就可以做到。模型元數(shù)據(jù)相對(duì)固定,使我們的解決方案相對(duì)規(guī)范。我們只需要生成不同的代碼就可以了。 當(dāng)然,這也是有前提的,一是開發(fā)DSL,進(jìn)行抽象整合需要成本。二是并不是所有的解決方案都適合使用DSL,比如一個(gè)門戶網(wǎng)站,可能相對(duì)固定的部門很少,可以定制的部分也很少,就不適合使用,如果對(duì)不適合使用的強(qiáng)制使用就會(huì)陷進(jìn)定制化陷阱。在設(shè)計(jì)和開發(fā)時(shí),一定要保留一定的靈活性,因?yàn)椴豢赡芩械拇a都能夠生成,你必須提供一定的擴(kuò)展性,保證能夠?qū)ι傻拇a進(jìn)行擴(kuò)展。另外就是一定要保證實(shí)現(xiàn)的規(guī)范,實(shí)現(xiàn)方式太多,會(huì)導(dǎo)致你的DSL過于復(fù)雜。有些時(shí)候你甚至需要舍棄一些實(shí)現(xiàn),舍棄一些需求?!昂?jiǎn)單的問題的解決應(yīng)該簡(jiǎn)單化,復(fù)雜問題的解決應(yīng)該可能化”(smalltalk的創(chuàng)始人AlianKay). 系列介紹 本系列一開始將通過一個(gè)案例簡(jiǎn)單的介紹DSL的開發(fā)流程,這個(gè)案例來(lái)源于DSL Tools Lab,主要介紹DSL的一些簡(jiǎn)單開發(fā)方法,其中也包括T4與DSL結(jié)合完成代碼生成,DSL工具的部署. 主要是完成一個(gè)狀態(tài)機(jī)的DSL應(yīng)用,具體我們會(huì)在接下來(lái)一一介紹。 對(duì)DSL的開發(fā)有過簡(jiǎn)單的了解后,我們會(huì)對(duì)完成一個(gè)實(shí)際使用的完整的開發(fā)工具的開發(fā)。在這個(gè)過程中也會(huì)包含介紹DSL設(shè)計(jì)和開發(fā)過程以及應(yīng)該注意的問題,當(dāng)然也會(huì)包括DSL以及VSX的一些比較深層次的應(yīng)用。 參考 Visual Studio DSL 工具特定領(lǐng)域開發(fā)指南 Doamin-Specific Development With Visual Studio DSL Tools Visual Studio DSL 入門 2 相信如果看過一上篇你已經(jīng)對(duì) dsl有了一定的了解,接下來(lái)我們就來(lái)開始我們的這個(gè)系列的入門,V Dsl在國(guó)內(nèi)可能使用的人少之又少,不過希望這個(gè)系列能夠使看到的人能夠?qū)sl有一定的了解,使之能夠成為產(chǎn)品方案選型時(shí)的一個(gè)參考,能夠?qū)﹂喿x的人有所幫助. 準(zhǔn)備環(huán)境 由于 2010并未正式發(fā)布,所以這一系列基于vs 2008 sp1進(jìn)行開發(fā),Dsl tools是包含在VSX當(dāng)中的,所以需要下載 Vistual Stutio.Net SDK 1.1安裝,下載地址為:/zh-cn/vsx/default(en-us).aspx 另外代碼生成采用的是T4,為了方便T4的編寫,需要下載T4編輯器/,遺憾的是V至今還沒有內(nèi)置T4編輯器,在vs 2010中也不會(huì)提供。 需求說明 我們完成的這個(gè)簡(jiǎn)單的Demo類似于UML中的狀態(tài)圖(Statechart Diagram), 這個(gè)狀態(tài)機(jī)由狀態(tài)(states)組成,各狀態(tài)由轉(zhuǎn)移(transitions)鏈接在一起。狀態(tài)是對(duì)象執(zhí)行某項(xiàng)活動(dòng)或等待某個(gè)事件時(shí)的條件。轉(zhuǎn)移是兩個(gè)狀態(tài)之間的關(guān)系,它由某個(gè)事件觸發(fā),然后執(zhí)行特定的操作或評(píng)估并導(dǎo)致特定的結(jié)束狀態(tài)。 狀態(tài)(State)的要素: 名稱: 將一個(gè)狀態(tài)與其他狀態(tài)區(qū)分開來(lái)的文本字符串;狀態(tài)也可能是匿名的,這表示它沒有名稱。 分類: 狀態(tài)分為初始狀態(tài)(initial state)和結(jié)束狀態(tài)(end state). 進(jìn)入/退出操作: 在進(jìn)入和退出狀態(tài)時(shí)所執(zhí)行的操作。 內(nèi)部轉(zhuǎn)移: 在不使?fàn)顟B(tài)發(fā)生變更的情況下進(jìn)行的轉(zhuǎn)移。 子狀態(tài): 狀態(tài)的嵌套結(jié)構(gòu),包括不相連的(依次處于活動(dòng)狀態(tài)的)或并行的(同時(shí)處于活動(dòng)狀態(tài)的)子狀態(tài)。 延遲的事件: 未在該狀態(tài)中處理但被延遲處理(即列隊(duì)等待由另一個(gè)狀態(tài)中的對(duì)象來(lái)處理)的一系列事件。 轉(zhuǎn)移(Transitions)的要素: 源狀態(tài): 轉(zhuǎn)移所影響的狀態(tài);如果對(duì)象處于源狀態(tài),當(dāng)對(duì)象收到轉(zhuǎn)移的觸發(fā)事件并且滿足警戒條件(如果有)時(shí),就可能會(huì)觸發(fā)輸出轉(zhuǎn)移。 事件觸發(fā)器: 使轉(zhuǎn)移滿足觸發(fā)條件的事件。當(dāng)處于源狀態(tài)的對(duì)象收到該事件時(shí)(假設(shè)已滿足其警戒條件),就可能會(huì)觸發(fā)轉(zhuǎn)移。 事件一般都有一個(gè)名稱,但是有些轉(zhuǎn)移沒有事件名稱,稱為自動(dòng)或隱式轉(zhuǎn)移. 警戒條件: 一種布爾表達(dá)式。在接收到事件觸發(fā)器而觸發(fā)轉(zhuǎn)移時(shí),將對(duì)該表達(dá)式求值;如果該表達(dá)式求值結(jié)果為 True,則說明轉(zhuǎn)移符合觸發(fā)條件;如果該表達(dá)式求值結(jié)果為False,則不觸發(fā)轉(zhuǎn)移。如果沒有其他轉(zhuǎn)移可以由同一事件來(lái)觸發(fā),該事件就將被丟棄。 操作: 可執(zhí)行的、不可分割的計(jì)算過程,該計(jì)算可能直接作用于擁有狀態(tài)機(jī)的對(duì)象,也可能間接作用于該對(duì)象可見的其他對(duì)象。 目標(biāo)狀態(tài)(可選): 在完成轉(zhuǎn)移后被激活的狀態(tài)。 參數(shù): 轉(zhuǎn)移可能有參數(shù),這個(gè)參數(shù)為事件觸發(fā)器的事件方法的參數(shù) 事先弄清楚這段說明是很重要的,因?yàn)槲覀兊哪P?,我們的元?shù)據(jù)都來(lái)源于需求問題的描述 計(jì)劃 一個(gè)簡(jiǎn)單的入門系列計(jì)劃大致包含幾下幾步: 1. 創(chuàng)建一個(gè)簡(jiǎn)單的DSL模型 2. 創(chuàng)建我們的元數(shù)據(jù)模型,包含狀態(tài)機(jī)(StateMachine),狀態(tài)(State),轉(zhuǎn)移(Transition).可能實(shí)際的會(huì)對(duì)我們需求有些取舍,比如不考慮子狀態(tài)等. 3. 創(chuàng)建相對(duì)我們的元數(shù)據(jù)模型的圖形展現(xiàn). 4.規(guī)范我們的模型和圖.添加規(guī)則(Rule)和驗(yàn)證(Validation) 5.在Visual Studio實(shí)驗(yàn)室環(huán)境中測(cè)試我們的Dsl項(xiàng)目 6.改善我們的用戶界面. 7.針對(duì)我們限定的元數(shù)據(jù)針對(duì)一個(gè)框架創(chuàng)建代碼生成. 8.創(chuàng)建安裝程序發(fā)布Dsl項(xiàng)目安裝包資源 1.DSL Tools Lab /DSLToolsLab 系列教程 2.臺(tái)灣微軟Paul的DSL系列視頻教程 /zh-tw/vstudio/cc963628.aspx 3.Domain-Specific Development with Visual Studio DSL Tools 目前知道的唯一一本關(guān)于專門關(guān)于Vs.NET DSL的書,有對(duì)應(yīng)的中文譯本. 4.VSX的一系列深入進(jìn)階 /blogs/divedeeper/default.aspx?PageIndex=1 Visual Studio DSL 入門 3-創(chuàng)建一個(gè)簡(jiǎn)單的DSL模型 從這節(jié)開始我們就開始我們的DSL之旅, 首先確保你已經(jīng)安裝了Visual Studio Sdk,并且使用的是Visual Studio 2008.我們先大概創(chuàng)建一個(gè)簡(jiǎn)單的DSL項(xiàng)目,通過這個(gè)項(xiàng)目來(lái)了解dsl的開發(fā)環(huán)境和流程.1. 打開VS.NET ,新建-項(xiàng)目, 點(diǎn)擊其它項(xiàng)目類型-擴(kuò)展性(Extensibility). 這里列出來(lái)了擴(kuò)展類型的項(xiàng)目,包括Addin,VSPackage,Dsl等項(xiàng)目類型,選擇Domain Specific Lan guage Designer”,點(diǎn)擊確定 2.接下來(lái)進(jìn)入DSL創(chuàng)建向?qū)?將會(huì)提供四種DSL模型模板提供我們選擇,其實(shí)他們只是給我們提供了不同的Sample提供查看,也方便我們更方便的開始. Class Diagrams 由UML類圖組成,包含類,接口,關(guān)系,組合,屬性,操作等. Component Models 組件模型,子組件組成的組件. Minimal Language 只包含一個(gè)簡(jiǎn)單的空的語(yǔ)言模型 Task Flow 創(chuàng)建類似UML狀態(tài)圖模型 3. 在這里我們選擇Minimal Language,并保持Language Name默認(rèn)即可,點(diǎn)擊下一步,設(shè)計(jì)Language的模型文件的后綴名和文件圖標(biāo)。如果你輸入的后綴名已經(jīng)被使用,中間的框中會(huì)列出搜索到的注冊(cè)的后綴名列表。在這里我們輸入sm作為后綴名,保持使用默認(rèn)的圖標(biāo). 4. 點(diǎn)擊下一步,進(jìn)入到產(chǎn)品設(shè)置,主要設(shè)計(jì)產(chǎn)品名稱,所屬公司,項(xiàng)目名稱空間.這些信息將會(huì)包含在最后生成的項(xiàng)目中,在最后的產(chǎn)品部署中起到作用。在這里我們不進(jìn)行更改,可以直接保持默認(rèn)即可. 5. 下一步進(jìn)入到簽名設(shè)置,在擴(kuò)展開發(fā)中任何需要部署的Package都需要強(qiáng)命名(將會(huì)注冊(cè)到GAC),可以選擇自動(dòng)創(chuàng)建一個(gè)Key,也可以選擇使用已有的key. 6. 我們選擇直接創(chuàng)建強(qiáng)命名key,點(diǎn)擊下一步,這是一個(gè)設(shè)置總結(jié)界面: 我們直接能查看到所有的設(shè)置信息,可以通過上一步下一步進(jìn)行更改,也可直接點(diǎn)擊左側(cè)的導(dǎo)航來(lái)定位更改,確認(rèn)無(wú)誤后,點(diǎn)擊完成。向?qū)?Wizard)會(huì)自動(dòng)給我們構(gòu)建項(xiàng)目.我們暫且不管生成的這些項(xiàng)目結(jié)構(gòu),切換到解決方案資源管理器,點(diǎn)擊上面的最后面的按鈕“轉(zhuǎn)換所有模板”(Transalte All Template).完成后,點(diǎn)擊Debug運(yùn)行,就會(huì)打開Visual Studio實(shí)驗(yàn)室環(huán)境(Experimental hive),也就是上面的Minimal Language界面,可以大概操作一下了,相當(dāng)神奇吧,這就完成了第一個(gè)DSL項(xiàng)目的開發(fā).同樣你也可以選擇其它三種模型,效果在上面已經(jīng)列出來(lái)了. 7. 我們?cè)賮?lái)看一下生成的項(xiàng)目結(jié)構(gòu),整個(gè)解決方案總共有兩以下兩個(gè)項(xiàng)目組成(其它有三個(gè),另外就是運(yùn)行后的Testing項(xiàng)目,稍后介紹). Dsl: 根據(jù)你的模型數(shù)據(jù)(DslDefinition.dsl文件)生成的有關(guān)模型的操作,包括模型關(guān)系,序列化,圖形,連接器等 DslPackage: 支撐Dsl能夠在V里運(yùn)行,以及和V交互的操作,包括菜單,工具條,游覽器等 Dsl項(xiàng)目設(shè)置成了針對(duì)DslPackage項(xiàng)目的友元程序集(通過AssemblyInfo的InternalsVisibleTo),DslPackage中可以直接訪問Dsl中的內(nèi)部成員,DslPackage其實(shí)也是根據(jù)DslDefinition.dsl生成的深入了解這兩個(gè)項(xiàng)目的結(jié)構(gòu)是非常有必要的,我們會(huì)在隨后的深入過程中介紹。 8. 查看這兩個(gè)項(xiàng)目,發(fā)現(xiàn)大部分都是由后綴名為tt的文件組成,這就是t4文件(Text Templating Transformation Toolkit),類似于asp,ruby這樣的解釋性語(yǔ)言,讀我們的模型生成cs代碼,可以看到每個(gè)tt文件都附屬了一個(gè)cs代碼文件.綁定到了每個(gè)t4文件可以右鍵運(yùn)行自定義工具Run Custom Tool,就會(huì)調(diào)用TextTemplatingFileGenerator解析t4模板文件生成目標(biāo)代碼,也可以向我們剛才那個(gè)點(diǎn)擊上面的按鈕轉(zhuǎn)換所有的模板文件. 9. 打開Dsl項(xiàng)目中的DslDefinition.dsl文件.(這是通常情況下我們使用的最重要的文件,包括我們的Dsl的所有的模型元素?cái)?shù)據(jù),它附屬的DslDefinition.dsl.Diagram是它的圖形顯示文件). 這就是模型設(shè)計(jì)的主區(qū)域,我們來(lái)看一下它的組成部分: 1). 工具條,這里包括模型,關(guān)系,圖形. 這個(gè)工具條與.Dsl文件關(guān)系。 2). 模型元數(shù)據(jù). 這些概念的東西我們?cè)谙乱磺袝?huì)介紹. 3). 圖形展現(xiàn). 設(shè)計(jì)模型的展現(xiàn)信息,通過中間的那條線與模型對(duì)應(yīng)起來(lái) 4). Dsl Details編輯窗口, 用來(lái)編輯Dsl相關(guān)的一些信息,比如關(guān)系。 5). 解決方案文件夾,注意上面的黃色區(qū)域就是”轉(zhuǎn)換所有模板“按鈕,點(diǎn)擊下面的Dsl Explorer頁(yè)簽,切換到Dsl瀏覽器. 這里會(huì)列出來(lái)當(dāng)前Dsl文件里的模型,模型元素Element,圖Shape,類型,連接器Connector,Connection Builders,以通讀對(duì)模型瀏覽器,工具條,序列化的設(shè)置。我們對(duì)Dsl的大部分設(shè)計(jì)都會(huì)在這里完成. Ok,就到這里,下次將介紹一些基礎(chǔ)概念. Visual Studio DSL 入門 4- 基本概念 剛接觸Visual Studio DSL時(shí),被它的基本理論概念迷惑了很長(zhǎng)時(shí)間, 我的建議是如果能夠很快的理解這些概念最好.如果短時(shí)間內(nèi)理解不了就大概了解下這些基礎(chǔ)概念,就沒有必要為了每一個(gè)概念一直深入,搞得自己頭疼,倒不如在以后的實(shí)踐中慢慢深入,理解并加深這些概念. 開發(fā)一個(gè)DSL需要?jiǎng)?chuàng)建的幾個(gè)不同的組成部分:域模型,圖形符號(hào),工具箱,資源管理器和屬性窗口,驗(yàn)證,序列化和部署,打開上一節(jié)我們創(chuàng)建的LanguageSm項(xiàng)目中的DslDefinition.dsl文件,可以看到在中心文檔區(qū)域有左右兩部分(兩個(gè)泳道). 1.左側(cè)是元數(shù)據(jù)模型(域模型). 也就是域類和域關(guān)系 2.右側(cè)是圖形符合,也就是圖形元素(Diagram Elements). 其實(shí)我們是在用DSL本身在創(chuàng)建DSL,這些描述本身也是在用DSL 另外,域模型與圖形符號(hào)之間通過連接器(Connectors)連接,域類之間可以通過關(guān)系relationships連接. 域模型 (Domain Model) 每一個(gè)DSL的核心都是一個(gè)域模型,它定義了語(yǔ)言所代表的各種概念,它們的屬性,以及它們之間的關(guān)系。在模型驅(qū)動(dòng)開發(fā)中,我們的模型要抽象出來(lái),并用DSL的語(yǔ)法描述出來(lái),這也就是用域模型來(lái)描述,只要我們有了域模型,工具箱,圖形展現(xiàn)都是基于域模型然則創(chuàng)建的。 域模型有兩個(gè)概念: 1.根域類(root Domain Class) 任何一個(gè)DSL有且只有一個(gè)根域類,它和你的圖形對(duì)應(yīng),這里說的圖形是整個(gè)圖形的概念。從我們上一節(jié)的項(xiàng)目中可以看到,我們創(chuàng)建的時(shí)候默認(rèn)就自動(dòng)創(chuàng)建了根域類(ExampleModel)和它對(duì)應(yīng)的圖形(ExampleShape)。 2.域類(Domain Class) 和根域類不一樣,ExampleElement是真正意義上的模型。并且它有一個(gè)屬性,名稱為Name,類型為String. 域關(guān)系(domain relationships) 1.嵌入關(guān)系(embedding relationship) 嵌入關(guān)系表示一個(gè)模型能夠嵌入在另外一個(gè)模型中。在我們的dsl中的可以找到嵌入關(guān)系ExampleModelHasElements,把ExampleModel和ExampleElement聯(lián)系起來(lái)(見下圖). 在ExampleModel這一端的屬性名為Elements,這個(gè)集合屬性是它包含所有的ExampleElement, 重?cái)?shù)為0.*,表達(dá)它可以包含零個(gè)或者多個(gè)ExampleElement, 域角色是指它在這個(gè)關(guān)系中扮演的角色,角色名你可以通過點(diǎn)擊域角色(這條線)在右面的屬性里面看到,角色名往往和這一端的源屬性名相反,和另外一端的屬性名一致。 在ExampleElement這一端的屬性名為ExampleModel,表示它所從屬的ExampleModel類型,重?cái)?shù)為1.1 ,表示它可以并且只可以從屬于一個(gè)ExampleModel. 簡(jiǎn)單來(lái)說,這個(gè)嵌入關(guān)系也就表示了在我們的上一切最后運(yùn)行起來(lái)的Dsl中,我們的ExampleModel模型中能夠放多個(gè)ExampleElement,對(duì)于每一個(gè)ExampleElement只能從屬于一個(gè)ExampleModel. 2.引用關(guān)系(reference relationship) 在我們的Dsl中看到引用關(guān)系ExempleElementReferencesTargets把兩個(gè)ExampleElements關(guān)系起來(lái),表示在兩個(gè)ExampleElement之間可以建立ExempleElementReferencesTarget關(guān)系,引用關(guān)系一般有圖形表示,所以在設(shè)計(jì)時(shí)通過拖動(dòng)一條線來(lái)把兩個(gè)模型關(guān)系起來(lái),和嵌入關(guān)系一樣,引用關(guān)系也可以設(shè)置多重性,表示是否允許和多個(gè)模型同時(shí)建立引用關(guān)系。在我們的例子中源和目標(biāo)相同,重?cái)?shù)為0.*,表示一個(gè)ExampleElement可以與多個(gè)其它的ExempleElement建立引用關(guān)系。 注意這里這不是代表著兩個(gè)ExampleElement之間可以建立多個(gè)重復(fù)的引用關(guān)系,而是指不同的ExampleElement之間。允許重復(fù)的關(guān)系需要在關(guān)系的屬性中設(shè)置Allows Duplicates為True.另外很重要的一點(diǎn),Dsl會(huì)對(duì)每個(gè)域關(guān)系生成一個(gè)單獨(dú)的類,模型中建立的每個(gè)關(guān)系都是這個(gè)類的一個(gè)實(shí)例。我們可以通過屬性中的Code下面屬性進(jìn)行設(shè)置來(lái)控制生成的代碼,我們可以設(shè)置GeneratesDoubleDerived屬性為True,每個(gè)關(guān)系會(huì)生成兩個(gè)類,父類ExampleModelHasElementsBase包含所有的實(shí)現(xiàn),子類ExampleModelHasElements是一個(gè)partial類,所以你可以重載父類的方法來(lái)實(shí)現(xiàn)你自己的邏輯。另外我們也可以通過這種機(jī)制來(lái)實(shí)現(xiàn)生成的代碼里實(shí)現(xiàn)某個(gè)我們自定義的接口。注意,同樣也可以在域類上進(jìn)行設(shè)置。 在這里我覺得有必要對(duì)幾個(gè)概念加強(qiáng)區(qū)分一下: 域類域模型: 域模型包含域類和域關(guān)系,域類代表領(lǐng)域中的不同的類型,域關(guān)系代表兩個(gè)域類中的關(guān)系信息。 (1) 域模型 -虛線里所所有的 (2) 域類Library (3) 域類Person (4) 域關(guān)系 (5)重?cái)?shù) * (表示在一個(gè)域模型中,一個(gè)Library可以有多個(gè)Person). (6)重?cái)?shù) 1 (表示一個(gè)Person,只能存在于一個(gè)Library中). (7)源角色 (8)目標(biāo)角色 域?qū)傩詫傩?在一個(gè)域模型中,一個(gè)域類可以有一堆域?qū)傩?,這是和領(lǐng)域掛鉤的,是對(duì)元數(shù)據(jù)的描述。但是對(duì)于每個(gè)域類,我們還可以在DSL設(shè)計(jì)器中的屬性編輯器中,也會(huì)列出來(lái)一些屬性,比如描述,名稱等。注意這里的名稱屬性和這個(gè)域類所具有的Name屬性是不一樣的。這里的屬性列出來(lái)的是域類的屬性,也就是這個(gè)域類叫什么名字. 而Dsl圖中列出來(lái)的是它的領(lǐng)域?qū)傩?,而且每個(gè)域?qū)傩云鋵?shí)也是一個(gè)元素,所以他本身也會(huì)有一些屬性,這里的Name其實(shí)就是它在圖中顯示出來(lái)的名字。 好了,今天就到這里,先消化下. Visual Studio DSL 入門 5-理解生成的域類和域關(guān)系 上一節(jié)我們大概介紹了一些V Dsl的域模型的一些基本的概念,這一節(jié)我們?cè)倩氐轿覀兩傻腖anuageSm項(xiàng)目,看一下生成的域類以及域關(guān)系,介紹一下Dsl運(yùn)行時(shí)的Store,然后再來(lái)介紹一下需要注意的一些關(guān)鍵點(diǎn)。為我們下一節(jié)具體設(shè)計(jì)我們自己的Dsl做最后的準(zhǔn)備. 1. 首先找到Dsl項(xiàng)目中模板DomainClasses.tt生成的DomainClasses.cs,我們來(lái)查看一下它由兩個(gè)類組成: 其實(shí)也就對(duì)應(yīng)著我們域模型中的根域類ExampleModel和域類ExampleElement.我們仔細(xì)再來(lái)看一下ExampleElement類的具體結(jié)構(gòu).可以發(fā)現(xiàn): 1).字段是Guid類型的,這樣更方便關(guān)系類中直接引用屬性,后續(xù)我們也會(huì)發(fā)現(xiàn)在驗(yàn)證,規(guī)則中也會(huì)經(jīng)常使用屬性的Guid字段變量來(lái)代表屬性. 2).我們看到上一節(jié)我們看到的關(guān)系生成的屬性,ExampleElement與ExampleModel的嵌入關(guān)系,生成了ExampleModel類型的ExampleModel屬性. ExampleElement與自身的引用關(guān)系,由于重?cái)?shù)是*,生成了強(qiáng)集合類型LinkedElementCollection屬性. 3).屬性中的Name代表域類的域?qū)傩訬ame。 2. 我們?cè)賮?lái)看一下域關(guān)系,找到DomainRelationships.tt生成的類文件DomainRelationships.cs,查看類圖,顯示類圖中的屬性為關(guān)系或者是組合關(guān)系: 1)可以看到域關(guān)系對(duì)應(yīng)的類通過Guid對(duì)應(yīng)的字段關(guān)聯(lián)域類. 2)通過上面的類圖,可以看到域關(guān)系類對(duì)應(yīng)的屬性與域類的關(guān)系,它分別存儲(chǔ)了關(guān)系對(duì)應(yīng)的源Source和目標(biāo)Target的屬性。 3)我們可以找到一些靜態(tài)方法,比如在ExampleModelHasElements類中: GetElements(ExampleModel) - 獲取關(guān)系中一個(gè)ExampleModel對(duì)應(yīng)的所有的ExampleElement GetExampleModel(ExampleElement) -獲取關(guān)系中一個(gè)ExampleElement對(duì)應(yīng)的ExampleModel 另外還可以通過GetLink,GetLinks, GetLinksToElements,獲取指定元素之間的關(guān)系。 3.很有必要在這里也對(duì)Dsl的運(yùn)行的機(jī)制有一些了解 ,那就必須在這里介紹一下Store. 1)在Dsl運(yùn)行期間,模型元素都被存儲(chǔ)在內(nèi)存中的Store中,Sotre也提供了一系列的操作:模型元素和關(guān)系的創(chuàng)建,操作,刪除,Redo/Undo,規(guī)則,事件等,相當(dāng)重要,在Dsl開發(fā)中經(jīng)常會(huì)涉及到Store的操作。 2)當(dāng)一個(gè)模型文件被打開時(shí),會(huì)自動(dòng)重建一個(gè)Store,并且加載模型文件中的所有的模型和關(guān)系的實(shí)例,這個(gè)過程我們會(huì)在后面介紹。 3) 每一個(gè)域類都繼承ModelElement,每個(gè)域關(guān)系都繼承自ElementLink(ElementLink其實(shí)也繼承于ModelElement). 在Store中加載的每個(gè)模型其實(shí)都是ModelEment的一個(gè)實(shí)例,每個(gè)域關(guān)系都是ElementLink的一個(gè)實(shí)例??梢酝ㄟ^Store甚至可以操作它們的屬性,監(jiān)聽創(chuàng)建,刪除等事件. 4.有一些細(xì)節(jié)性的應(yīng)該注意的問題在這里零散的總結(jié)一下: 1).區(qū)分兩個(gè)域類是嵌入關(guān)系還是引用關(guān)系,可以考慮這域類在模型瀏覽器里的展現(xiàn),如果嵌入在模型瀏覽器中(Model Explorer)那就可以采用嵌入關(guān)系,否則就是引用關(guān)系. 2).關(guān)系的重?cái)?shù)雖然可以任意選擇,但是在有些情況下會(huì)有些限制,比如在嵌入式關(guān)系中: 嵌入關(guān)系目標(biāo)角色的重?cái)?shù)可為One 或者是ZeroOne,因?yàn)橐粋€(gè)ModelElement只能被嵌入一次. 如果一個(gè)ModelElement是多個(gè)嵌入關(guān)系中的目標(biāo)角色,那么目標(biāo)角色的重?cái)?shù)必須都為ZeroOne,因?yàn)樗荒茉谕粫r(shí)間在一個(gè)關(guān)系中扮演目標(biāo)角色。 在一個(gè)完整的域模型中,每個(gè)域類(根域類除外)必須是一個(gè)嵌入關(guān)系的目標(biāo),不然就不能夠構(gòu)成一個(gè)完整的模型樹,也就不能夠處理序列化 當(dāng)然,可能大家會(huì)對(duì)這些規(guī)則有些不知所措,沒關(guān)系,你可以不理這些規(guī)則,按照你的方式去設(shè)計(jì),在保存或者是驗(yàn)證(右鍵Validate All)時(shí),會(huì)在下面的錯(cuò)誤窗口提示你的。 3)每個(gè)域類都應(yīng)該有Name Domain Property.可以通過從工具欄拖Named Domain Class創(chuàng)建域類,自動(dòng)帶出此域?qū)傩?,也可以手?dòng)添加域?qū)傩?,然后指定域?qū)傩缘腎s Element Name 為True,此屬性的值會(huì)在序列化處理時(shí)使用. Visual Studio DSL 入門 6-DSL的圖形表示1 到現(xiàn)在為止,我們還是只是介紹模型相關(guān)的東西,還沒有接觸到Dsl的模型的展現(xiàn),對(duì)于一個(gè)Dsl來(lái)說,沒有圖形展現(xiàn)也是可行的,不過對(duì)于一個(gè)開發(fā)工具來(lái)說,要提供一種方式來(lái)操作我們的元數(shù)據(jù),Visual Studio DSL在圖形展現(xiàn)這方面提供了不錯(cuò)的支持,不過對(duì)于復(fù)雜的Dsl來(lái)說,圖形的展現(xiàn)往往需求很復(fù)雜,現(xiàn)在的圖形化支持在一定程度上也未必能夠滿足一些特定的需求, 有總比沒有好,期望微軟會(huì)在這方面會(huì)有所加強(qiáng)。 還是以我們創(chuàng)建的LanguageSm項(xiàng)目為例,我們大概介紹一下界面表示相關(guān)的概念,打開DslDefinition.dsl文件,這次我們看泳道(也就是樹線)的右邊: 一. 圖表 我們看最下面的LanguageSmDiagram,這就是圖表元素,它是存儲(chǔ)形狀和連接器映射的容器,代表設(shè)計(jì)界面自身,映射到模型的根域類(圖形元素Diagram Elements都是與模型相對(duì)應(yīng)的),也就是映射到我們例子里的ExampleModel,我們來(lái)看一下圖表的屬性: 在這里,我們可以對(duì)圖表的外觀,代碼,文檔,公開樣式屬性,資源幾個(gè)方面進(jìn)行屬性設(shè)置,Dsl會(huì)收集設(shè)置的這些信息,然后根據(jù)T4模板,在Dsl項(xiàng)目的Generate Code文件夾下面生成Diagram類,我們也可以對(duì)這個(gè)類進(jìn)行擴(kuò)展,實(shí)現(xiàn)圖表方面的一些自定義,比如設(shè)置背景圖,顯示網(wǎng)絡(luò)等。如果你想實(shí)現(xiàn)Dsl模型的自己的界面表示方式,也需要實(shí)現(xiàn)自己的圖表元素Diagram類. 二.編輯器 編輯器分為兩種類型:(圖形)設(shè)計(jì)器和自定義編輯器.編輯器的定義在Dsl資源管理器(Dsl Explorer)中的“編輯器”(editor)節(jié)點(diǎn)下,這里的定義的屬性用于生成EditorFactory類(熟悉VSX的應(yīng)該知道,我們會(huì)在后面介紹),工具箱等,我們來(lái)看一下默認(rèn)的設(shè)計(jì)器的屬性: 這里需要提示一下,在dsl設(shè)計(jì)的過程中,有很多時(shí)候需要dsl瀏覽器和屬性對(duì)應(yīng)操作使用,可以通過右鍵屬性來(lái)進(jìn)行設(shè)置。 屬性里設(shè)置了編輯器對(duì)應(yīng)的圖表元素,編輯器的GUID,根域類,以及存儲(chǔ)Dsl模型的文件擴(kuò)展名,與文件關(guān)聯(lián)的圖標(biāo)?;蛟S你不太明白這些屬性代表什么意義,沒有關(guān)系,以后會(huì)明白的。 我們?cè)诘谝还?jié)就說過, Dsl模型并不一定要有圖形編輯器的,我們也可以在這里添加我們自定義的編輯器,你可以右鍵刪除默認(rèn)的Editor,然后在根結(jié)點(diǎn)LanguageSm上右鍵添加自定義編輯器,然后設(shè)置上面說的那些屬性,然后實(shí)現(xiàn)自己的DocView,在這里有詳細(xì)流程,具體的方法我們也會(huì)在后面詳細(xì)介紹. 三.形狀 形狀是Dsl圖形符號(hào)的重點(diǎn),因?yàn)樾螤詈湍P驮匾灰粚?duì)應(yīng)(前面說的ExampleShape是一個(gè)幾何形狀,和根域類對(duì)應(yīng)),可以使模型元素形象化,這也是Vs.Net DSL圖形化DSL的特點(diǎn). 形狀又分為以下五個(gè)不同的類型,這五個(gè)形狀在工具箱上都有,可以直接拖動(dòng)到圖形區(qū)域創(chuàng)建對(duì)應(yīng)的形狀,建議現(xiàn)在沒有必要太去細(xì)化,而只需要記住他們的樣式,能夠按需所有,具體怎么設(shè)置還是到使用的時(shí)候再去研究: 1.幾何形狀(GeometryShape) 左側(cè)為形狀的模型,右側(cè)為調(diào)試后運(yùn)行的顯示模型,形狀中的文本裝飾器NameDecorator就是用來(lái)控制我們顯示圖形中的文本,你可以查看裝飾器的屬性,控制文本的顯示,包括文本,顯示位置等. 對(duì)于幾何形狀,除了文本裝飾器以外,你還可以添加IconDecorator(裝飾圖形上顯示圖標(biāo)),ExpandCollapseDecorator(裝飾圖形的展開收縮) 2.隔間形狀(CompartmentShape) 隔間形狀是帶有隔間的幾何形狀,一個(gè)隔間形狀有可以有多個(gè)隔間: 同樣,對(duì)于隔間形狀,你也可以象幾何形狀那樣添加其它的裝飾器. 3.圖像形狀(ImageShape) 圖像形狀是顯示圖形非輪廓的形狀: 可以看到,圖像形狀顯示的和我們普通的幾何形狀是不一樣的,我們可以針對(duì)圖象開關(guān)設(shè)置顯示的圖像和圖標(biāo)資源,我們來(lái)看一下上面的圖像形狀的屬性,在最下面我們定義了顯示的圖標(biāo): 4.端口(PortShape) 端口是依附在形狀輪廓上,并只能繞輪廓移動(dòng)的特殊形狀,除此之外,和普通的幾何形狀沒有區(qū)別。 5.泳道(Swimlane) 泳道用來(lái)將圖表分割成行或例,我們看下面的狀態(tài)流程圖: 參考資源 1. Visual Stuido DSL 工具特定領(lǐng)域開發(fā)指南 2.Using WPF As The Designer Surface In DSL Tools Gokhan AltinorenVisual Studio DSL 入門 7-DSL的圖形表示2 在上一節(jié)介紹了 dsl的圖形符號(hào),其中包括圖表,編輯器,形狀.在這一節(jié),我們來(lái)看一下圖形符號(hào)與元數(shù)據(jù)之間的關(guān)系,他們是怎么映射在一起的. 模型元素由形狀來(lái)表示,而域關(guān)系則用連接器(Connectors)來(lái)表示.圖形映射定義了模型元素通過形狀可視化表示出來(lái),而連接器映射定義了鏈接如何通過連接器可視化表示出來(lái). 形狀映射 我們先來(lái)看一下形狀映射,接著打開我們的LanguageSm項(xiàng)目中的Dsl文件. 選中域類ExampleElement與圖形ExampleShape之間的線,可看下面的Dsl details: 這個(gè)窗口有兩個(gè)tab,General tab主要是定義域類和圖形間的連接, 可以選擇形狀,域類,設(shè)置他們之間的映射關(guān)系,Parent element path(父元素路徑)指出了引用的域類的邏輯父元素,以及當(dāng)前形狀應(yīng)當(dāng)以哪個(gè)圖表元素作為父親. 為什么需要指定父元素路徑呢?因?yàn)樵O(shè)計(jì)器在運(yùn)行時(shí),所有的圖表元素(除了圖表本身),都必須有父圖表元素(可以是圖表或形狀),這樣這個(gè)圖表才能夠知道自己放在哪里,所以我們?cè)谶@里需要指定形狀被創(chuàng)建后哪個(gè)圖表元素將作為它的父親. 父元素路徑使用簡(jiǎn)單的路徑語(yǔ)法來(lái)表示整個(gè)元素和鏈接結(jié)構(gòu),在我們這個(gè)例子中,它指出了從ExampleElement出發(fā)順著ExampleModelHasElements.ExampleModel/!ExampleModel這條中徑得到的元素對(duì)對(duì)應(yīng)的圖表元素,就是形狀的父元素所在的圖表,在這個(gè)例子里,也就是圖表本身ExampleModel元素,因?yàn)槲覀兊腅xampleShape是直接放在圖形上的。 另外兩個(gè)可設(shè)置的項(xiàng),具有自定義的父形狀(Has custome Parent Shape),具有自定義的父元素(Has custom parent element),當(dāng)選中時(shí),生成的代碼會(huì)添加自定義的代碼段,你必須實(shí)現(xiàn)對(duì)應(yīng)的方法才能夠編譯通過,在指定的方法里,你可以自已返回父元素和父形狀. 隱藏行號(hào) 復(fù)制代碼 ? 1. if(element is global:Company.LanguageSm.ExampleElement)2. 3. / Method:4. / private DslDiagrams:NodeShape CreateShapeForExampleElement(ExampleElement newElement)5. / 6. / 7. / must be implemented in a partial class of LanguageSmDiagram. Given an instance of ExampleElement,8. / the method should return a new shape or connector instance that should be associated with this element. If no shape or connector should be created, the method should return null.9. DslDiagrams:NodeShape newShape = CreateShapeForExampleElement(global:Company.LanguageSm.ExampleElement)element);10. if(newShape != null) newShape.Size = newShape.DefaultSize; / set default shape size11. return newShape;12. 你必須在LanguageSmDiagram的partial類里面實(shí)現(xiàn)這個(gè)GetShapForExampleElement方法才能夠編譯通過. 裝飾器映射 我們?cè)賮?lái)看一下Decorator tab,這里主要是映射屬性和裝飾器,在某些情況下,裝飾器的外觀可能會(huì)需要隨著模型信息的更改而動(dòng)態(tài)更改,裝飾器映射主要是來(lái)定義這一行為。 上面顯示的是Dsl中的ExampleShape的Name裝飾器的裝飾器映射,顯示屬性(Display Property)主要是針對(duì)文本裝飾器(text decorator),在這里也就是用來(lái)設(shè)置需要顯示的文本對(duì)應(yīng)的域類的域?qū)傩? 可見性篩選器(Visibility Fi
溫馨提示
- 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 投標(biāo)文件供貨方案(3篇)
- 胸科麻醉病例分析
- 金店內(nèi)部安全方案(3篇)
- 母嬰護(hù)理課件模板
- 住宅小區(qū)車位共享租賃管理合同范本
- 廠房電力系統(tǒng)安全保障與應(yīng)急預(yù)案合同
- 車庫(kù)所有權(quán)抵押交易合同范本
- 餐飲行業(yè)廚師學(xué)徒勞動(dòng)合同范本
- 資產(chǎn)重組項(xiàng)目保證擔(dān)保合同條款設(shè)計(jì)原則
- 中秋線上教學(xué)課件
- 建筑工程項(xiàng)目管理人員工作標(biāo)準(zhǔn)
- (完整文本版)新概念英語(yǔ)第一冊(cè)單詞表默寫版1-144
- 醫(yī)師入職測(cè)考試試題答案(臨床)
- 鋼結(jié)構(gòu)門頭專項(xiàng)施工方案
- SOP標(biāo)準(zhǔn)作業(yè)指導(dǎo)書excel模板
- 染色作業(yè)指導(dǎo)書
- 空間機(jī)器人地面遙操作的關(guān)鍵技術(shù)研究
- 人工智能倫理規(guī)則
- 工程物探-第五章電法勘探課件
- 婦產(chǎn)科護(hù)理學(xué)教材(課后思考題參考答案)
- 二年級(jí)數(shù)學(xué)無(wú)紙化監(jiān)測(cè)試題
評(píng)論
0/150
提交評(píng)論