HOW TO:從 UML 模型產生檔案
從 UML 模型可以產生程式碼、結構描述、文件、資源和任何類型的其他成品。從 UML 模型產生文字檔的便利方法之一,是使用文字範本。這些方法可讓您將程式碼內嵌到您要產生的文字中。
主要情節共有三種:
從功能表命令或軌跡產生檔案。您可以定義可在 UML 模型上使用的 Visual Studio 命令。
從應用程式產生檔案。您可以撰寫可讀取 UML 模型及產生檔案的應用程式。
在設計階段產生。您可以使用模型來定義某些應用程式功能,並在您的 Visual Studio 方案中產生程式碼、資源等項目。
本主題的末段將討論如何使用文字產生。如需詳細資訊,請參閱程式碼產生和 T4 文字範本。
從功能表命令產生檔案
您可以使用 UML 功能表命令中的前置處理文字範本。在文字範本的程式碼內,或是個別部分類別中,您可以讀取由圖表所檢視的模型。
如需這些功能的詳細資訊,請閱讀下列主題:
當您從其中一個模型圖表啟始作業時,下列範例所示範的方法可讓您從單一模型產生文字。若要處理個別內容中的模型,請考慮使用 Visual Studio Modelbus 來存取模型及其項目。
範例
若要執行此範例,請建立 Visual Studio Extension (VSIX) 專案。此範例中使用的專案名稱為 VdmGenerator。在 source.extension.vsixmanifest 檔案中按一下 [加入內容],然後將類型欄位設為 [MEF 元件] 以及參考目前專案的來源路徑。如需如何設定此專案類型的詳細資訊,請參閱HOW TO:在模型圖表上定義功能表命令。
在專案中加入包含下列程式碼的 C# 檔案。此類別會定義將出現在 UML 類別圖表上的功能表命令。
using System;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
namespace VdmGenerator
{
[Export(typeof(ICommandExtension))]
[ClassDesignerExtension]
public class GenerateVdmFromClasses : ICommandExtension
{
[Import] public IDiagramContext DiagramContext { get; set; }
public void Execute(IMenuCommand command)
{
// Initialize the template with the Model Store.
VdmGen generator = new VdmGen(
DiagramContext.CurrentDiagram.ModelStore);
// Generate the text and write it.
System.IO.File.WriteAllText
(System.IO.Path.Combine(
Environment.GetFolderPath(
Environment.SpecialFolder.Desktop),
"Generated.txt")
, generator.TransformText());
}
public void QueryStatus(IMenuCommand command)
{
command.Enabled = command.Visible = true;
}
public string Text
{ get { return "Generate VDM"; } }
}
}
下列檔案為文字範本。它會為模型中的每個 UML 類別產生一行文字,並為每個類別中的各個屬性產生一行文字。用以讀取模型的程式碼會內嵌在文字中,以 <# ... #> 分隔。
若要建立此檔案,請以滑鼠右鍵按一下 [方案總管] 中的專案,指向 [加入],然後按一下 [新增項目]。選取 [前置處理過的文字範本]。此範例的檔案名稱應為 VdmGen.tt。此檔案的 [自訂工具] 屬性應為 [TextTemplatingFilePreprocessor]。如需前置處理文字範本的詳細資訊,請參閱使用 T4 文字範本在執行階段產生文字。
<#@ import namespace="Microsoft.VisualStudio.Uml.Classes" #>
<#
foreach (IClass classElement in store.AllInstances<IClass>())
{
#>
Type <#= classElement.Name #> ::
<#
foreach (IProperty attribute in classElement.OwnedAttributes)
{
#>
<#= attribute.Name #> : <#=
attribute.Type == null ? ""
: attribute.Type.Name #>
<#
}
}
#>
文字範本會產生 C# 部分類別,這會成為您 Visual Studio 專案的一部分。在個別檔案中,加入相同類別的其他 partial 修飾詞。此程式碼會為範本提供 UML 模型存放區的存取權:
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
namespace VdmGenerator
{
public partial class VdmGen
{
private IModelStore store;
public VdmGen(IModelStore s)
{ store = s; }
}
}
若要測試專案,請按 F5。Visual Studio 的新執行個體隨即啟動。在此執行個體中,開啟或建立包含類別圖表的 UML 模型。將部分類別加入至圖表,並將部分屬性加入至每個類別。在圖表中按一下滑鼠右鍵,然後按一下範例命令 [Generate VDM]。此命令會建立檔案 C:\Generated.txt。檢查此檔案。其內容應類似於下列文字,但同時會列出您自己的類別和屬性:
Type Class1 ::
Attribute1 : int
Attribute2 : string
Type Class2 ::
Attribute3 : string
從應用程式產生檔案
您可以從可讀取 UML 模型的應用程式來產生檔案。執行此作業時,使用 Visual Studio Modelbus 存取模型及其項目,是最有彈性而建全的方法。
您也可以使用基本 API 來載入模型,並使用上一節所說明的技術將模型傳遞至文字範本。如需載入模型的詳細資訊,請參閱 HOW TO:讀取程式碼中的 UML 模型。
在設計階段產生檔案
如果您的專案具有將 UML 解譯成程式碼的標準方法,您可以建立文字範本,以便在您的專案中從 UML 模型產生程式碼。您通常會有一個包含 UML 模型專案的方案,以及應用程式程式碼的一個或多個專案。每個程式碼專案都可能包含數個會產生程式碼、資源和組態檔的範本,視模型的內容而定。開發人員只要按一下 [方案總管] 工具列中的 [轉換所有範本],即可執行所有範本。程式碼通常會以部分類別的形式產生,以便整合手動撰寫的部分。
此類型的 Visual Studio 專案可透過範本形式散發,而使每個小組成員皆可以相同方式建立從模型產生程式碼的專案。範本通常是擴充套件的一部分,其中包含模型的驗證條件約束,以確保能夠符合產生程式碼的前置條件。
產生檔案的概略程序
若要在專案中加入範本,請在 [加入新檔案] 對話方塊中選取 [文字範本]。大部分的專案類型都可加入範本,但模型專案則否。
範本檔的 [自訂工具] 屬性應為 TextTemplatingFileGenerator,副檔名應為 .tt。
範本至少應有一個輸出指示詞:
<#@ output extension=".cs" #>
請根據專案的語言來設定副檔名欄位。
若要讓您的範本所產生的程式碼能夠存取模型,請撰寫組件讀取 UML 模型所需的 <#@ assembly #> 指示詞。請使用 ModelingProject.LoadReadOnly() 開啟模型。如需詳細資訊,請參閱HOW TO:讀取程式碼中的 UML 模型。
範本會在您儲存時以及按一下 [方案總管] 工具列中的 [轉換所有範本] 時執行。
如需此範本類型的詳細資訊,請參閱使用 T4 文字範本在設計階段產生程式碼。
在一般專案中,您會有數個可從相同模型產生不同檔案的範本。每個範本的第一個部分都會相同。若要減少此重複性,請將通用部分移至個別的文字檔中,然後使用每個範本中的指示詞 <#@include file="common.txt"#> 加以叫用。
您也可以定義特製化的指示詞處理器,以便將參數提供給文字產生程序。如需詳細資訊,請參閱自訂 T4 文字轉換。
範例
此範例會為來源模型中的每個 UML 類別產生一個 C# 類別。
若要設定此範例的 Visual Studio 方案
在新的方案中,建立模型專案中的 UML 類別圖表。
按一下 [架構] 功能表中的 [新增圖表]。
選取 [UML 類別圖表]。
依照提示建立新的方案和模型專案。
從工具箱中拖曳 [UML 類別] 工具,以將部分類別加入至圖表。
儲存檔案。
在相同的方案中建立 C# 或 Visual Basic 專案。
- 在 [方案總管] 中,以滑鼠右鍵按一下方案、指向 [加入],然後按一下 [新增專案]。在 [已安裝的範本] 下方按一下 [Visual Basic] 或 [Visual C#],然後選取專案類型,如 [主控台應用程式]。
將純文字檔加入至 C# 或 Visual Basic 專案。此檔案將會包含您要撰寫數個文字範本時所共用的程式碼。
- 在 [方案總管] 中,以滑鼠右鍵按一下專案,並指向 [加入],然後按一下 [新增項目]。選取 [文字檔]。
插入下列區段中顯示的文字。
將文字範本檔加入至 C# 或 Visual Basic 專案。
- 在 [方案總管] 中,以滑鼠右鍵按一下專案,並指向 [加入],然後按一下 [新增項目]。選取 [文字範本]。
將後續的程式碼插入文字範本檔中。
儲存文字範本檔。
檢查附屬檔案中的程式碼。其中應包含模型中每個 UML 類別的類別。
在 Visual Basic 專案中,按一下 [方案總管] 工具列中的 [顯示所有檔案]。
展開 [方案總管] 中的範本檔節點。
共用文字檔的內容
在此範例中,此檔案的名稱是 SharedTemplateCode.txt,其所在資料夾與文字範本相同。
<# /* Common material for inclusion in my model templates */ #>
<# /* hostspecific allows access to the Visual Studio API */ #>
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="Microsoft.VisualStudio.Uml.Interfaces.dll"#>
<#@ assembly name="Microsoft.VisualStudio.ArchitectureTools.Extensibility.dll"#>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="Microsoft.VisualStudio.Uml.Classes" #>
<#@ import namespace="Microsoft.VisualStudio.ArchitectureTools.Extensibility" #>
<#@ import namespace="Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml" #>
<#+ // Note this is a Class Feature Block
///<summary>
/// Text templates are run in a common AppDomain, so
/// we can cache the model store that we find.
///</summary>
private IModelStore StoreCache
{
get { return AppDomain.CurrentDomain.GetData("ModelStore") as IModelStore; }
set { AppDomain.CurrentDomain.SetData("ModelStore", value); }
}
private bool CacheIsOld()
{
DateTime? dt = AppDomain.CurrentDomain
.GetData("latestAccessTime") as DateTime?;
DateTime t = dt.HasValue ? dt.Value : new DateTime();
DateTime now = DateTime.Now;
AppDomain.CurrentDomain.SetData("latestAccessTime", now);
return now.Subtract(t).Seconds > 3;
}
///<summary>
/// Find the UML modeling project in this solution,
/// and load the model.
///</summary>
private IModelStore ModelStore
{
get
{
// Avoid loading the model for every template:
if (StoreCache == null || CacheIsOld())
{
// Use Visual Studio API to find modeling project:
EnvDTE.DTE dte = (EnvDTE.DTE) ((IServiceProvider) this.Host)
.GetService(typeof(EnvDTE.DTE));
EnvDTE.Project project = null;
foreach (EnvDTE.Project p in dte.Solution.Projects)
{
if (p.FullName.EndsWith(".modelproj"))
{
project = p;
break;
}
}
if (project == null) return null;
// Load UML model into this AppDomain
// and access model store:
IModelingProjectReader reader =
ModelingProject.LoadReadOnly(project.FullName);
StoreCache = reader.Store;
}
return StoreCache;
}
}
#>
文字範本檔的內容
.tt 檔案中會有下列文字。此範例會從模型中的 UML 類別,產生 C# 檔案的類別。但您可以產生任何類型的檔案。產生的檔案所使用的語言,與撰寫文字範本程式碼的語言無關。
<#@include file="SharedTemplateCode.txt"#>
<#@ output extension=".cs" #>
namespace Test
{
<#
foreach (IClass c in ModelStore.AllInstances<IClass>())
{
#>
public partial class <#=c.Name#>
{ }
<#
}
#>
}
如何使用文字產生
當您使用模型在需求或架構的層級上進行設計時,才是模型真正發揮功能的時候。您可以將文字範本運用在某些將高階概念轉換成程式碼的工作上。在許多情況下,這都無法達成 UML 模型中的項目與程式碼的類別或其他組件之間的一對一對應。
此外,轉換情形也會隨您的問題網域而不同;模型與程式碼之間並沒有通用的對應。
以下是從模型產生程式碼的一些範例:
產品線。Fabrikam, Inc.是一家建置及安裝機場行李處理系統的公司。許多軟體的安裝流程都十分類似,但軟體組態則須取決於安裝的行李處理機器,以及輸送帶連結這些組件的方式。在合約開始時,Fabrikam 的分析人員首先討論機場管理的需求,然後使用 UML 活動圖表勾勒出硬體計劃。開發小組透過此模型產生了組態檔、程式碼、計劃和使用者文件。他們對程式碼進行手動附加和調整,完成工作。他們藉由工作累積經驗,進而擴充產生的內容範圍。
模式。Contoso, Ltd 的開發人員經常建置網站,並使用 UML 類別圖表設計巡覽配置。每個網頁各由一個類別所代表,而關聯性則代表巡覽連結。開發人員從模型產生了網站的許多程式碼。每個網頁各對應於數個類別和資源檔項目。此方法的好處是,每個網頁的建構均符合單一模式,因而能達到優於手寫程式碼的可靠性和彈性。模式係用以產生範本,模型則用以制定可變層面。
結構描述。Humongous Insurance 在全球各地擁有數以千計的系統。這些系統使用不同的資料庫、語言和介面。中央架構小組負責從內部發行企業概念和流程的模型。地區小組可利用這些模型,產生其資料庫與交換結構描述的組件、程式碼中的宣告等項目。模型的圖形表示可協助小組討論相關提案。小組可建立多份圖表,以顯示適用於不同企業區域之模型的子集。他們也可使用不同的顏色凸顯可能會變更的區域。
重要的成品產生技術
在前幾個範例中,模型運用在各種隨企業類型而變動的用途上,且模型項目 (如類別和活動) 的定義皆隨著應用程式而不同。以下是您從模型產生成品時有用的技術。
設定檔。即使在單一企業區域中,項目型別的解譯也可能會變動。以網站圖表為例,有些類別可能代表網頁,有些則代表內容區塊。為了方便使用者記下這些不同之處,請定義造型。造型也可讓您附加適用於該類型項目的其他屬性。造型可封裝在設定檔中。如需詳細資訊,請參閱HOW TO:定義要擴充 UML 的設定檔。
在範本程式碼中,您可以輕鬆地存取對物件定義的造型。例如:
public bool HasStereotype(IClass c, string profile, string stereo) { return c.AppliedStereotypes.Any (s => s.Profile == profile && s.Name == stereo ); }
具有條件約束的模型。您所能建立的模型,並非全都適用於各種用途。以 Fabrikam 的機場行李模型為例,有登機登記櫃台而沒有連外輸送帶,就是錯誤的模型。您可以定義驗證函式,以協助使用者檢視這些條件約束。如需詳細資訊,請參閱HOW TO:定義 UML 模型的驗證條件約束。
保留手動變更。只有部分方案檔可從模型產生。在大部分的情況下,您都必須能夠手動加入或調整產生的內容。但在重新執行範本轉換時,保留這些手動變更就顯得十分重要了。
若您的範本是以 .NET 語言產生程式碼,則應產生部分類別,讓開發人員能夠加入方法和程式碼。以成對的形式產生各類別也有其效用:包含方法的抽象基底類別,和僅包含建構函式的繼承類別。這可讓開發人員覆寫方法。若要能夠覆寫初始設定,則應在個別方法中執行覆寫,而不是在建構函式中。
若範本產生了 XML 和其他類型的輸出,要將手動內容保留在產生的內容以外,可能會難得多。其中一種方法是在建置流程中建立會結合兩個檔案的工作。另一個方法是讓開發人員調整產生範本的本機複本。
將程式碼移至個別組件中。建議您不要在範本中撰寫龐大的程式碼主體。最好讓產生的內容與計算分開,而文字範本並不充分支援程式碼編輯。
如果您必須執行大量計算以產生文字,請在個別的組件中建置這些函式,並從範本呼叫其方法。