Поделиться через


Практическое руководство. Создание файлов из модели UML

В модели UML можно создавать программный код, схемы, документы, ресурсы и другие артефакты. Удобно создавать текстовые файлы из модели UML с использованием шаблонов текста. В этом случае можно вставлять программный код в текст, который необходимо создать.

Существует три возможных сценария.

  • Создание файлов из команды меню или жеста. Для этого нужно определить команду Visual Studio, доступную в моделях UML.

  • Создание файлов из приложения. Нужно создать приложение, читающее модели UML и создающее файлы.

  • Создание файлов во время разработки. Модель используется для определения некоторых функциональных возможностей приложения, создания кода. ресурсов и т. д. в решении Visual Studio.

В конце этого раздела рассказывается, как использовать метод создания текста. Дополнительные сведения см. в разделе Создание кода и текстовые шаблоны T4.

Создание файлов из команды меню

В команде меню UML можно использовать предварительно обработанные шаблоны текста. В коде шаблона текста или в отдельном разделяемом классе можно прочитать модель, отображаемую на схеме.

Дополнительные сведения об использовании этих возможностей см. в следующих разделах.

Подход, продемонстрированный в следующем примере, подходит для создания текста из одной модели, когда операция инициируется из одной из схем модели. Чтобы обработать модель в отдельном контексте, рекомендуется использовать Visual Studio Modelbus для получения доступа к модели и ее элементам.

Пример

Для выполнения этого примера создайте проект с расширением Visual Studio (VSIX). В этом примере используется проект с именем 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 #> 
<#
     }
   }
#>

Текстовый шаблон создает разделяемый класс C#, который становится частью проекта Visual Studio. В отдельном файле нужно добавить другое частичное объявление того же класса. Этот код предоставляет шаблон с возможностью доступа в хранилище моделей 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, содержащую схему классов. Добавьте на схему несколько классов, а в каждый класс — несколько атрибутов. Щелкните правой кнопкой мыши схему и выберите в качестве примера команду Создать VDM. Эта команда создает файл C:\Generated.txt. Проверьте этот файл. Его содержимое должно напоминать следующий текст, но с перечислением пользовательских классов и атрибутов.

Type Class1 ::
          Attribute1 : int 
          Attribute2 : string 
Type Class2 :: 
          Attribute3 : string 

Создание файлов из приложения

Можно создать фалы из приложения для чтения модели UML. Самый гибкий и надежный метод доступа к модели и ее элементам в этих целях — это Visual Studio Modelbus.

Кроме того, для загрузки модели и передачи модели текстовым шаблонам с помощью технологий, описанных в предыдущем подразделе, можно использовать базовый API-интерфейс. Дополнительные сведения о загрузке модели см. в разделе Практическое руководство. Чтение модели UML в программном коде.

Создание файлов во время разработки

Если стандартным методом интерпретации UML в проекте является код, можно создать текстовые шаблоны, позволяющие создавать код из модели UML внутри проекта. Как правило, имеется решение, которое содержит проект модели UML и один или несколько проектов для кода приложения. Каждый проект кода может содержать несколько шаблонов, создающих код программы, ресурсы и файлы конфигурации на основе содержимого модели. Разработчик может запустить все шаблоны, щелкнув Преобразовать все шаблоны на панели инструментов обозревателя решений. Программный код, как правило, создается в форме разделяемых классов, так как это облегчает интеграцию созданных вручную частей.

Проект Visual Studio такого вида можно распространять в форме шаблона, чтобы каждый участник команды мог создавать проекты, генерирующие код из модели аналогичным образом. Как правило, шаблон — это часть пакета расширения, включающая ограничения проверки модели, чтобы гарантировать соблюдение предусловий кода создания.

Общая процедура создания файлов

  • Чтобы добавить шаблон в проект, выберите Текстовый шаблон в диалоговом окне "Добавить новый файл". Шаблон можно добавить в проект практически любого типа, за исключением проектов моделирования.

  • Свойство "Пользовательские инструменты" файла шаблона должно иметь значение TextTemplatingFileGenerator, расширение имени файла должно быть .tt.

  • Шаблон должен иметь, по меньшей мере, директиву output.

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

    Задайте в поле расширения значение, соответствующее языку проекта.

  • Чтобы разрешить коду создания в шаблоне доступ к модели, создайте для всех сборок, необходимых для прочтения модели UML, директивы <#@ assembly #>. Для открытия модели используйте ModelingProject.LoadReadOnly(). Дополнительные сведения см. в разделе Практическое руководство. Чтение модели UML в программном коде.

  • Шаблон выполняется при сохранении и выборе команды Преобразовать все шаблоны на панели инструментов обозревателя решений.

  • Дополнительные сведения об этом типе шаблона см. в разделе Создание кода во время разработки с помощью текстовых шаблонов T4.

  • В стандартном проекте имеется несколько шаблонов, позволяющих создавать из одной модели разные файлы. Первая часть всех шаблонов одинаковая. Во избежание дублирования переместите совпадающие части в отдельных текстовый файл и вызывайте его по мере надобности в каждом шаблоне с использованием директивы <#@include file="common.txt"#>.

  • Кроме того, можно определить специализированный процессор директив, позволяющий предоставлять параметры в процессе создания текста. Дополнительные сведения см. в разделе Настройка преобразования текста T4.

Пример

В этом примере показано создание класса C# для каждого класса UML в исходной модели.

Настройка решения 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. В этом примере в файле C# классы создаются из UML-классов модели. Можно, однако, создавать файлы любого типа. Язык созданного файла не связан с языком, на котором написан код текстового шаблона.

<#@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, должна предоставляться возможность создания разделяемых классов, чтобы разработчики могли добавлять методы и код. Полезно создавать каждый класс в виде пары: абстрактный базовый класс с методами и наследующий класс, который содержит только конструктор. Это позволяет разработчикам переопределять методы. Чтобы разрешить переопределение инициализации, это делается не в конструкторах, а в отдельном методе.

    Если с помощью шаблона создается XML-код и другие выходные данные, отделить внесенные вручную изменения от автоматически созданного содержимого может оказаться нелегко. Для этого можно создать задачу в процессе построения, которая объединяет два файла. Кроме того, разработчики могут скорректировать локальную копию шаблона создания.

  • Перемещение кода в отдельные сборки. Не рекомендуется создавать в шаблонах большие объемы кода. Предпочтительнее отделить созданное содержимое от вычислений; кроме того, стоит отметить, что текстовые шаблоны предоставляют ограниченные возможности редактирования кода.

    Приходится выполнять объемные вычисления для создания текста, выполнять построение функций в отдельной сборке и вызывать соответствующие методы из шаблона.