방법: UML 모델에서 파일 생성

UML 모델에서 프로그램 코드, 스키마, 문서, 리소스 및 임의 종류의 다른 아티팩트를 생성할 수 있습니다. UML 모델에서 텍스트 파일을 생성하는 편리한 방법 중 하나는 텍스트 템플릿을 사용하는 것입니다. 텍스트 템플릿을 사용하면 생성할 텍스트 내에 프로그램 코드를 포함할 수 있습니다.

다음과 같은 세 가지 기본 시나리오가 있습니다.

  • 메뉴 명령에서 파일 생성(또는 제스처에서 파일 생성): UML 모델에서 사용할 수 있는 Visual Studio 명령을 정의합니다.

  • 응용 프로그램에서 파일 생성: UML 모델을 읽고 파일을 생성하는 응용 프로그램을 작성합니다.

  • 디자인 타임에 파일 생성: 모델을 사용하여 응용 프로그램의 일부 기능을 정의하고 Visual Studio 솔루션 내에서 코드, 리소스 등을 생성합니다.

이 항목의 끝에서는 텍스트 생성 사용 방법에 대해 설명합니다. 자세한 내용은 코드 생성 및 T4 텍스트 템플릿을 참조하십시오.

메뉴 명령에서 파일 생성

UML 메뉴 명령 내에서 전처리 텍스트 템플릿을 사용할 수 있습니다. 텍스트 템플릿의 코드 내에서 또는 별도의 partial 클래스에서 다이어그램에 표시된 모델을 읽을 수 있습니다.

이러한 기능에 대한 자세한 내용은 다음 항목을 참조하십시오.

다음 예제에서 보여 주는 방법은 모델 다이어그램 중 하나에서 작업을 시작하는 경우 단일 모델에서 텍스트를 생성하는 데 적합합니다. 별도의 컨텍스트에서 모델을 처리하려면 Visual Studio Modelbus를 사용하여 모델과 모델 요소에 액세스하는 것이 좋습니다.

예제

이 예제를 실행하려면 VSIX(Visual Studio Extension) 프로젝트를 만듭니다. 이 예제에서 사용되는 프로젝트 이름은 VdmGenerator입니다. source.extension.vsixmanifest 파일에서 콘텐츠 추가를 클릭하고 형식 필드를 MEF 구성 요소와 현재 프로젝트를 참조하는 소스 경로로 설정합니다. 이 형식의 프로젝트를 설정하는 방법에 대한 자세한 내용은 방법: 모델링 다이어그램의 메뉴 명령 정의를 참조하십시오.

다음 코드가 포함된 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 #> 
<#
     } 
   }
#>

이 텍스트 템플릿은 Visual Studio 프로젝트의 일부가 되는 C# partial 클래스를 생성합니다. 별도의 파일에서 동일한 클래스의 다른 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를 사용하여 모델을 로드한 다음 이전 단원에서와 같은 방법을 사용하여 이 모델을 텍스트 템플릿에 전달할 수도 있습니다. 모델 로드에 대한 자세한 내용은 방법: 프로그램 코드에서 UML 모델 읽기를 참조하십시오.

디자인 타임에 파일 생성

프로젝트에 UML을 코드로 해석하는 표준 메서드가 있는 경우 프로젝트 내에서 UML 모델을 기초로 코드를 생성하는 데 사용할 수 있는 텍스트 템플릿을 만들 수 있습니다. 일반적으로 솔루션에는 UML 모델 프로젝트와 하나 이상의 응용 프로그램 코드용 프로젝트가 포함됩니다. 각 코드 프로젝트에는 모델의 내용에 따라 프로그램 코드, 리소스 및 구성 파일을 생성하는 몇 개의 템플릿이 포함될 수 있습니다. 개발자는 솔루션 탐색기 도구 모음에서 모든 템플릿 변환을 클릭하여 모든 템플릿을 실행할 수 있습니다. 프로그램 코드는 대개 partial 클래스 형태로 생성되므로 수동으로 작성된 요소를 통합하기가 쉽습니다.

이 종류의 Visual Studio 프로젝트는 템플릿 형태로 배포할 수 있으므로 팀의 모든 멤버가 모델에서 코드를 생성하는 프로젝트를 동일한 방식으로 만들 수 있습니다. 일반적으로 이 템플릿은 생성 코드의 사전 조건이 충족되는지 확인하기 위해 모델에 대한 유효성 검사 제약 조건을 포함하는 확장 패키지의 일부입니다.

파일 생성 절차 개요

  • 프로젝트에 템플릿을 추가하려면 새 파일 추가 대화 상자에서 텍스트 템플릿을 선택합니다. 모델링 프로젝트를 제외한 대부분의 프로젝트 형식에 템플릿을 추가할 수 있습니다.

  • 템플릿 파일의 사용자 지정 도구 속성은 TextTemplatingFileGenerator이고 해당 파일 확장명은 .tt여야 합니다.

  • 템플릿에는 다음과 같은 output 지시문이 하나 이상 있어야 합니다.

    <#@ output extension=".cs" #>

    extension 필드는 프로젝트의 언어에 따라 설정합니다.

  • 템플릿의 생성 코드에서 모델에 액세스할 수 있도록 하려면 UML 모델을 읽는 데 필요한 어셈블리에 대한 <#@ assembly #> 지시문을 작성합니다. 모델을 열려면 ModelingProject.LoadReadOnly()를 사용합니다. 자세한 내용은 방법: 프로그램 코드에서 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는 전 세계에서 수천 대의 시스템을 사용하고 있습니다. 이러한 시스템에서 사용하는 데이터베이스, 언어 및 인터페이스는 각기 다릅니다. 중앙 아키텍처 팀에서는 비즈니스 개념 및 프로세스의 모델을 내부적으로 게시합니다. 로컬 팀은 이러한 모델에서 데이터베이스의 여러 부분을 생성하고, 스키마, 프로그램 코드의 선언 등을 교환합니다. 모델을 그래픽으로 나타내면 팀이 제안 사항을 보다 쉽게 논의할 수 있습니다. 팀에서는 각기 다른 비즈니스 영역에 적용되는 모델 하위 집합을 보여 주는 여러 다이어그램을 만듭니다. 또한 색을 사용하여 변경되기 쉬운 영역을 강조 표시합니다.

아티팩트 생성을 위한 중요 기술

이전 예제에서 모델은 다양한 비즈니스 종속 목적에 사용되며, 클래스 및 동작 등의 모델링 요소에 대한 해석은 응용 프로그램에 따라 달라집니다. 다음 기술은 모델에서 아티팩트를 생성할 때 유용합니다.

  • 프로필: 같은 비즈니스 영역 내에서도 요소 형식의 해석이 달라질 수 있습니다. 예를 들어 웹 사이트 다이어그램에서 일부 클래스는 웹 페이지를 나타내는 반면 다른 클래스는 콘텐츠 블록을 나타낼 수 있습니다. 사용자가 이러한 차이점을 쉽게 기록할 수 있도록 하려면 스테레오타입을 정의합니다. 스테레오타입은 해당 종류의 요소에 적용되는 추가 속성을 연결할 수 있게도 해 줍니다. 스테레오타입은 프로필 내에 패키지됩니다. 자세한 내용은 방법: 프로필을 정의하여 UML 확장을 참조하십시오.

    템플릿 코드에서는 개체에 대해 정의된 스테레오타입에 액세스하기가 쉽습니다. 예를 들면 다음과 같습니다.

    public bool HasStereotype(IClass c, string profile, string stereo)
    { return c.AppliedStereotypes.Any
       (s => s.Profile == profile && s.Name == stereo ); }
    
  • 제약 조건이 적용된 모델: 만들 수 있는 모든 모델이 모든 용도에 적당한 것은 아닙니다. 예를 들어 Fabrikam의 공항 수하물 모델에서 출구 컨베이어 없이 체크 인 데스크를 두는 것은 올바르지 않습니다. 사용자가 이러한 제약 조건을 쉽게 파악할 수 있도록 유효성 검사 기능을 정의할 수 있습니다. 자세한 내용은 방법: UML 모델에 대한 유효성 검사 제약 조건 정의를 참조하십시오.

  • 수동 변경 내용 유지: 모델에서는 솔루션 파일의 일부만 생성할 수 있습니다. 대부분의 경우에는 생성된 내용을 수동으로 추가하거나 조정할 수 있어야 합니다. 하지만 이러한 수동 변경 내용은 템플릿 변환이 다시 실행될 때도 유지되어야 합니다.

    .NET 언어로 코드를 생성하는 템플릿에서는 개발자가 메서드 및 코드를 추가할 수 있도록 partial 클래스를 생성해야 합니다. 또한 각 클래스를 메서드가 포함되는 추상 기본 클래스와 생성자만 포함되는 상속 클래스의 쌍으로 생성하는 것이 유용합니다. 이렇게 하면 개발자가 메서드를 재정의할 수 있습니다. 초기화를 재정의할 수 있도록 하려면 생성자 대신 별도의 메서드에서 초기화를 수행합니다.

    템플릿에서 XML과 그 밖의 출력 형식을 생성하는 경우에는 수동 내용을 생성된 내용과 분리하기가 더 어려울 수 있습니다. 이를 해결하는 한 가지 방법은 빌드 프로세스에 두 파일을 결합하는 작업을 만드는 것입니다. 또 다른 방법은 개발자가 생성 템플릿의 로컬 복사본을 조정하는 것입니다.

  • 코드를 별도의 어셈블리로 이동: 템플릿에서 많은 양의 코드 본문을 작성하는 것은 좋지 않습니다. 생성된 내용은 계산과 분리하는 것이 좋으며 텍스트 템플릿은 코드 편집용으로 사용하는 것이 좋습니다.

    대신 텍스트를 생성하기 위해 상당히 많은 계산을 수행해야 하는 경우에는 해당 기능을 별도의 어셈블리에 빌드하고 템플릿에서 해당 메서드를 호출합니다.