共用方式為


了解模型、類別和關聯性

特定領域語言 (DSL) 是由其 DSL 定義檔,以及您可能撰寫的任何自訂程式碼所定義。 DSL 解決方案中的大部分程式碼都是從這個檔案產生。

本主題說明 DSL 定義的中央功能。

DSL 定義

當您開啟 Dsl\DslDefinition.dsl 時,Visual Studio 視窗看起來像下圖。

dsl designer

DSL 定義中最重要的資訊會顯示在 DSL 定義圖表中。 其他也屬於 DslDefinition.dsl 的資訊會顯示在 DSL Explorer 中,這通常會出現在圖表的一側。 您可以使用圖表來處理最常見的工作,並使用 DSL Explorer 進行更進階的自訂。

DSL 定義圖表會顯示定義模型元素的領域類別,以及定義模型元素之間連結的關聯性。 其也會顯示用來向使用者顯示模型元素的圖形和連接器。

dsl designer with swimlane

當您在 DSL 定義中選取項目時,圖表或 DSL Explorer 中的項目會顯示在 [屬性] 視窗中。 其他資訊可能會顯示在 [DSL 詳細資料] 視窗中。

模型是 DSL 的執行個體

模型是使用者所建立 DSL 的執行個體。 模型包含模型元素,這些是您所定義領域類別的執行個體,以及元素之間的連結,這些是您所定義領域關聯的執行個體。 模型也可以具有圖形和連接器,其會顯示圖表上的模型元素和連結。 DSL 定義包含圖形類別、連接器類別,以及圖表的類別。

DSL 定義也稱為領域模型。 DSL 定義或領域模型是特定領域語言的設計階段表示法,而模型則是特定領域語言的執行階段具現化。

定義模型元素的領域類別

領域類別可用來建立領域的各種元素,而領域關聯是元素之間的連結。 其為元素和連結的設計階段表示法,這些元素和連結會在建立模型時,由設計特定語言的使用者具現化。

此圖顯示音樂庫 DSL 使用者所建立的模型。 音樂專輯會以包含歌曲清單的方塊來表示。 演出者會以圓角方塊代表,並連線到他們演出的專輯。

Instance model of generated DSL

DSL 定義會分隔兩個層面。 模型圖表上模型元素的外觀是使用圖形類別和連接器類別來定義。 模型中攜帶的資訊是使用領域類別和領域關聯來定義。

下圖顯示音樂媒體櫃 DSL 定義中的領域類別和關聯性。

Embedding and Reference relationships

此圖顯示四個領域類別:音樂、專輯、演出者和歌曲。 網域類別會定義領域屬性,例如 Name、Title 等等。 在執行個體模型中,這些屬性中的一些值會顯示在圖表上。

類別之間有領域關聯:MusicHasAlbums、MusicHasArtists、AlbumbHasSongs 和 ArtistAppearedOnAlbums。 關聯性具有多重性,例如 1..1、0..*。 例如,每首歌曲都必須透過 AlbumHasSongs 關聯性與一張專輯完全相關。 每張專輯都可以有任意數目的歌曲。

重新排列 DSL 定義圖

請注意,領域類別可在 DSL 定義圖表上出現數次,如同此圖片中的專輯一樣。 一律會有一個主要檢視,且可以有一些參考檢視。

若要重新排列 DSL 定義圖表,您可以:

  • 使用 [帶入樹狀結構] 和 [分割樹狀結構] 命令,交換主要檢視和參考檢視。 以滑鼠右鍵按一下單一領域類別,以查看這些命令。

  • 按 CTRL+Up 和 CTRL+Down 來重新排序領域類別和圖形類別。

  • 使用每個圖形右上角的圖示摺疊或展開類別。

  • 按一下領域類別底部的減號 (-) 來摺疊樹狀結構的部分。

繼承

領域類別可以使用繼承來進行定義。 若要建立繼承衍生,請按一下 [繼承] 工具,按一下衍生類別,然後按一下基底類別。 模型元素具有在其本身領域類別上定義的所有屬性,以及繼承自基底類別的所有屬性。 其也會繼承其在關聯性中的角色。

關聯性、圖形和連接器之間也可以使用繼承。 繼承必須保留在相同的群組內。 圖形無法繼承自領域類別。

[網域關聯性]

模型元素可透過關聯性連結。 連結一律為二進位;其只連結兩個元素。 不過,任何元素都可以有許多其他物件的連結,且同一組元素之間甚至可以有多個連結。

就像您可以定義不同的元素類別一樣,您可以定義不同的連結類別。 連結的類別稱為領域關聯。 領域關聯會指定其執行個體可以連線的元素類別。 關聯性的每個結尾稱為角色,而領域關聯會定義兩個角色的名稱,以及關聯性本身的名稱。

領域關聯有兩種:內嵌關聯性和參考關聯性。 在 DSL 定義圖表上,內嵌關聯性在每個角色都有實線,而參考關聯性則具有虛線。

內嵌關聯性

模型中的每個元素 (除了其根目錄之外) 都是一個內嵌連結的目標。 因此,整個模型會形成內嵌連結的單一樹狀結構。 內嵌關聯性代表內含項目或擁有權。 以這種方式相關的兩個模型元素也稱為父系和子系。 子系會內嵌在父系中。

內嵌連結通常不會明確顯示為圖表上的連接器。 相反地,其通常會以內含項目表示。 模型的根是由圖表表示,而內嵌在其中的元素會顯示為圖表上的圖形。

在此範例中,根類別 Music 與 Album 具有內嵌的 MusicHasAlbums 關聯性,該關聯性將 AlbumHasSongs 內嵌至 Song。 歌曲會顯示為每個專輯內清單中的項目。 Music 與 Artist 類別也有內嵌 MusicHasArtists,其執行個體也會顯示為圖表上的圖形。

根據預設,內嵌元素會在刪除其父代時自動刪除。

當模型以 XML 形式儲存至檔案時,除非您已自訂序列化,否則內嵌元素會巢狀於其父代內。

注意

內嵌與繼承不同。 內嵌關聯性中的子系不會繼承父系的屬性。 內嵌是模型元素之間的連結類型。 繼承是類別之間的關聯性,且不會建立模型元素之間的連結。

內嵌規則

執行個體模型中的每個元素都必須只是一個內嵌連結的目標,但模型根目錄除外。

因此,每個非抽象領域類別 (根類別除外) 都必須是至少一個內嵌關聯性的目標,或者其必須從基底類別繼承內嵌。 類別可以是兩個或多個內嵌的目標,但其執行個體模型元素一次只能有一個父代。 從目標到來源的多重性必須是 0..1 或 1..1。

總管會顯示內嵌樹狀結構

您的 DSL 定義也會建立總管,使用者會隨其模型圖表看到。

Generated explorer of DSL

總管會顯示模型中的所有元素,即使是您尚未定義任何圖形的元素也一樣。 其會顯示元素和內嵌關聯性,但不會顯示參考關聯性。

若要查看元素的網域屬性值,使用者會在模型圖表或模型總管中選取元素,然後開啟 [屬性] 視窗。 其會顯示所有網域屬性,包括未顯示在圖表上的屬性。 在此範例中,每個 Song 都有 Title 和 Genre,但圖表上只會顯示 Title 的值。

參考關聯性

參考關聯性代表任何未內嵌的關聯性。

參考關聯性通常在圖表上顯示為圖形之間的連接器。

在模型的 XML 標記法中,兩個元素之間的參考連結會使用 Moniker 來表示。也就是說,Moniker 是可唯一識別模型中每個元素的名稱。 每個模型元素的 XML 節點都包含一個節點,會指定關聯性的名稱和另一個元素的 Moniker。

Roles

每個網域關聯性都有兩個角色,一個來源角色和一個目標角色。

在下圖中,Publisher 領域類別與 PublisherCatalog 領域關聯之間的行是來源角色。 領域關聯與 Album 領域類別之間的行是目標角色。

Roles and properties.

當您撰寫周遊模型的程式碼時,與關聯性相關聯的名稱特別重要。 例如,當您建置 DSL 方案時,產生的類別 Publisher 具有屬性 Catalog,這是專輯的集合。 類別 Album 具有屬性 Publisher,該屬性是 Publisher 類別的單一執行個體。

當您在 DSL 定義中建立關聯性時,會為屬性和關聯性名稱提供預設值。 不過,您可以變更這些值。

多重性

多重性會指定有幾個元素可以在領域關聯中具有相同角色。 在此範例中,Catalog 角色上的零對多 (0..*) 多重性設定會指定 Publisher 領域類別的任何執行個體可以具有您要為其提供的任意數目 PublisherCatalog 關聯性連結。

在圖表上鍵入或修改 [屬性] 視窗中的 Multiplicity 屬性,以設定角色的多重性。 下表描述此屬性的設定。

多重性類型 描述
0..* (零對多) 領域類別的每個執行個體可以有多個關聯性執行個體,或沒有關聯性的執行個體。
0..1 (零對一) 領域類別的每個執行個體不能有超過一個關聯性執行個體,或沒有關聯性的執行個體。
1..1 (一) 領域類別的每個執行個體都可以有一個關聯性的執行個體。 您無法從角色類別的任何執行個體建立一個以上此關聯性的執行個體。 如果啟用驗證,當角色類別的任何執行個體沒有關聯性執行個體時,就會顯示驗證錯誤。
1..* (一對多) 在具有這個多重性的角色上,類別的每個執行個體都可以有多個關聯性執行個體,且每個執行個體都必須至少有一個關聯性執行個體。 如果啟用驗證,當角色類別的任何執行個體沒有關聯性執行個體時,就會顯示驗證錯誤。

領域關聯即類別

連結在 Store 中會表示為 LinkElement 的執行個體,這是 ModelElement 的衍生類別。 您可以在領域模型圖表中定義領域關聯的屬性。

您也可以將關聯性設為其他關聯性的來源或目標。 在領域模型圖表中,以滑鼠右鍵按一下領域關聯,然後按一下 [顯示為類別]。 隨即會出現額外的類別方塊。 然後,您可以將關聯性與其連線。

您可以部分依據繼承來定義關聯性,就像您搭配領域類別的方式一樣。 選取衍生關聯性,然後在 [屬性] 視窗中設定 [基底關聯性]

衍生關聯性會特製化其基底關聯性。 其連結的領域類別應該衍生自基底關聯性,或與依基底關聯性連結的類別相同。 在模型中建立衍生關聯性的連結時,其為衍生和基底關聯性的執行個體。 在程式碼中,您可以使用基底或衍生類別所產生的屬性,瀏覽至連結的相反端。