共用方式為


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 方案

  1. 在新的方案中,建立模型專案中的 UML 類別圖表。

    1. 按一下 [架構] 功能表中的 [新增圖表]。

    2. 選取 [UML 類別圖表]。

    3. 依照提示建立新的方案和模型專案。

    4. 從工具箱中拖曳 [UML 類別] 工具,以將部分類別加入至圖表。

    5. 儲存檔案。

  2. 在相同的方案中建立 C# 或 Visual Basic 專案。

    • 在 [方案總管] 中,以滑鼠右鍵按一下方案、指向 [加入],然後按一下 [新增專案]。 在 [已安裝的範本] 下方按一下 [Visual Basic] 或 [Visual C#],然後選取專案類型,如 [主控台應用程式]。
  3. 將純文字檔加入至 C# 或 Visual Basic 專案。 此檔案將會包含您要撰寫數個文字範本時所共用的程式碼。

    • 在 [方案總管] 中,以滑鼠右鍵按一下專案,並指向 [加入],然後按一下 [新增項目]。 選取 [文字檔]。

    插入下列區段中顯示的文字。

  4. 將文字範本檔加入至 C# 或 Visual Basic 專案。

    • 在 [方案總管] 中,以滑鼠右鍵按一下專案,並指向 [加入],然後按一下 [新增項目]。 選取 [文字範本]。

    將後續的程式碼插入文字範本檔中。

  5. 儲存文字範本檔。

  6. 檢查附屬檔案中的程式碼。 其中應包含模型中每個 UML 類別的類別。

    1. 在 Visual Basic 專案中,按一下 [方案總管] 工具列中的 [顯示所有檔案]。

    2. 展開 [方案總管] 中的範本檔節點。

共用文字檔的內容

在此範例中,此檔案的名稱是 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 和其他類型的輸出,要將手動內容保留在產生的內容以外,可能會難得多。 其中一種方法是在建置流程中建立會結合兩個檔案的工作。 另一個方法是讓開發人員調整產生範本的本機複本。

  • 將程式碼移至個別組件中。 建議您不要在範本中撰寫龐大的程式碼主體。 最好讓產生的內容與計算分開,而文字範本並不充分支援程式碼編輯。

    如果您必須執行大量計算以產生文字,請在個別的組件中建置這些函式,並從範本呼叫其方法。