Содержание


Преобразования UML- C++ в IBM Rational Systems Developer и Rational Software Architect

Итеративная разработка кода С++ из UML-модели с параллельным улучшением модели и кода.

Comments

Необходимые условия и общая информация о процессе

В этой статье рассказывается о том, как программист в C++ может использовать структуры данных C++ при разработке приложений даже в том случае, если он создает модели с помощью Unified Modeling Language (UML). Чтобы извлечь пользу из чтения этой статьи, достаточно иметь базовые знания UML и программных продуктов IBM® Rational® Software Architect и IBM® Rational® Systems Developer, однако авторы предполагают, что вы умеете выполнять преобразования и применять профили и стереотипы. Процесс можно разделить на следующие этапы:

  1. Начинаем с создания простой UML-модели в IBM Rational Systems Developer;
  2. Применяем к этой модели профиль C++, чтобы можно было использовать при моделировании структуры данных, специфичные для C++;
  3. Импортируем в модель библиотеку типов C++, чтобы можно было использовать примитивные типы C++;
  4. Генерируем код и бегло просматриваем его;
  5. Затем добавляем тело в метод в каком-нибудь классе;
  6. Добавляем в модель несколько незначительных деталей, чтобы понаблюдать за тем, как при повторном применении преобразования UML - C++ сохраняются сделанные вами изменения в коде и модели.

Создание простой UML-модели

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

Применение профиля C++

Для моделирования, например, таких специфических для С++ элементов, как структуры, объединения, определяемые типы typedef и т. п., необходимо применить к UML-модели профиль С++. Профиль С++ поставляется вместе с инструментом преобразования UML-C++. Чтобы применить профиль, выполните следующие шаги:

  1. Убедитесь, что находитесь в представлении Modeling;
  2. Выберите модель, а затем перейдите в представление Properties;
  3. Выберите категорию Profiles из списка в левой части представления Properties;
  4. Нажмите кнопку Add Profileи выберите профиль C++ Transformation в списке Deployed Profile в диалоговом окне Select Profile. (см. рисунки 1 и 2.)
Рисунок 1. Применение профиля C++ (CPP)
Рисунок 1. Применение профиля C++ (CPP)
Рисунок 1. Применение профиля C++ (CPP)
Рисунок 2. Выбор профиля C++
Рисунок 2. Выбор профиля  C++
Рисунок 2. Выбор профиля C++

Импорт библиотеки типов C++

UML предоставляет очень ограниченный набор встроенных типов. Это, как правило, такие типы, как Boolean, Integer, String и UnlimitedNatural. Большинство языков программирования, в том числе C++, предлагают гораздо более богатый набор примитивов. При создании моделей для C++ вам часто будут нужны встроенные примитивные типы языка С++ при присваивании типа атрибутам, параметрам, типам возврата операции и так далее. Чтобы импортировать библиотеку моделирования C++, которая поставляется вместе с инструментом преобразования C++, выполните следующие действия:

  1. Нажмите правой кнопкой мыши на UML-модели в панели обозревателя проектов Project Explorer;
  2. Выберите из контекстного меню команду Import Model Library, как показано на рисунке 3;
Рисунок 3. Импорт библиотеки типов C++
Импорт библиотеки типов C++
Импорт библиотеки типов C++
  1. В окне Import Model Library выберите опцию Deployed Library, а затем выберите из раскрывающегося списка пункт C++ Types , как показано на рисунке 4.
Рисунок 4. Выбор импортируемой библиотеки типов C++
Выбор библиотеки типов С++
Выбор библиотеки типов С++

Теперь вы готовы к моделированию специфичных для С++ элементов, которые не имеют эквивалентов в UML. Пример.

Создание простой модели завода, производящего автомобили

Приступим к созданию простой UML-модели, показанной на рисунке 5. Существуют различные способы создания этой модели, но вам предлагается следовать показанной на рисунке схеме. Например:

  • Эта простая модель содержит класс Vehicle (Транспортное средство), базовый для классов Bus (Автобус) и Car (Автомобиль);
  • Классы Bus (Автобус), Car (Автомобиль) и Vehicle (Транспортное средство) создаются в UML-пакете с именем Vehicles (Транспортные средства), это на схеме не показано;
  • Аналогично, классы Engine (Двигатель) и Wheels (Колеса) создаются в UML-пакете с именем Parts (Компоненты), что также не показано на схеме;
  • Класс Car (Автомобиль) связан ассоциацией "содержит" с классом Engine (Двигатель);
  • На этом воображаемом заводе классы Car (Автомобиль) и Engine (Двигатель) являются неразделимыми, поскольку ни один автомобиль не может обойтись без двигателя;
  • Классы Car (Автомобиль) и Bus (Автобус) связаны ассоциацией "собираются в одно целое" с классом Wheels (Колеса);
  • В этом примере колеса могут существовать без автомобиля, а автомобиль может существовать без колес - по крайней мере, пока не будет закончена сборка.
Рисунок 5. Пример - простая UML-модель завода по производству автомобилей
Рисунок 5. Пример - простая UML-модель завода по производству автомобилей
Рисунок 5. Пример - простая UML-модель завода по производству автомобилей

Создание элементов С++ в модели

  1. Затем мы создаем UML-пакет с именем Strategy на уровне модели;
  2. В пакете Strategy определим маршруты и исходные точки для автобусов;
    1. Создайте класс с именем Route, который будет представлять маршрут, и класс Address, который будет представлять некоторый адрес, соответствующий точке отправления автобусного маршрута;
    2. Address должен быть элементом C++ "структура", а не обычным классом.
  3. Давайте теперь уточним UML-модель, указав, что маршрут назначается для каждого автобуса. Это можно сделать, добавив ассоциацию "прилагается" от класса Bus в пакете Vehicles к классу Route, как показано на рисунке 6;
  4. Одним из основных свойств маршрута является пункт отправления. Значит, нужно добавить атрибут с именем startingPoint и типом Address классу Route.
Рисунок 6. Содержимое нового UML-пакета Strategy
Рисунок 6. Содержимое нового UML-пакета Strategy
Рисунок 6. Содержимое нового UML-пакета Strategy

Обратите внимание, что на рисунке 6 Address представляет собой класс <<cpp_struct>>. Для создания стереотипного элемента с именем Address и типом <<cpp_struct>> выполните следующие шаги:

  1. Создайте UML-класс и присвойте ему имя Address;
  2. Примените к только что созданному классу стереотип cpp_struct;
    1. Чтобы применить стереотип к какому-либо элементу UML, необходимо переключиться на представление Properties для данного элемента;
    2. Выберите пункт Stereotypes из списка категорий в левой части окна представления, а затем нажмите кнопку Apply Stereotypes, как показано на рисунке 7.
Рисунок 7. Применение стереотипа
Рисунок 7. Применение стереотипа
Рисунок 7. Применение стереотипа
  1. Выберите из списка стереотипов, применимых для этого элемента, стереотип cpp_struct . Кроме того, просмотрите и другие элементы списка, просто для справки, на будущее.

Очень скоро вы увидите, что при преобразовании этой модели в код UML-класс Address со стереотипом <<cpp_struct>> будет сгенерирован как элемент структура, а не как класс.

Настройка преобразования и генерация кода

Прежде чем вы сможете сгенерировать код C++ из своей модели, необходимо определить параметры для преобразования UML - C++ путем создания конфигурационного файла преобразования.

Создание конфигурационного файла преобразования

Вот один из способов, который можно использовать для выполнения этой задачи:

  1. Выберите в меню команды File > New > Others, а затем выберите элемент transformation configuration в папке Transformations;
  2. В открывшемся окне мастера создания конфигурации преобразования New Transform Configuration wizard укажите имя для нового конфигурационного файла. Для этого упражнения укажите имя tc1;
  3. Выберите тип преобразования и проект, в котором будет сохранен конфигурационный файл;
    1. Для выбора типа преобразования разверните список IBM Rational Transformations , а затем выберите из списка UML to C++;
    2. Чтобы сохранить конфигурационный файл для этого упражнения, используйте уже существующий проект UML-модели.
  4. Затем перейдите к следующей странице мастера, нажав кнопку Next;
  5. На вкладке Source and Target:
    1. Выберите UML-модель в качестве источника;
    2. Создайте новый управляемый проект C++ в качестве назначения.
  6. Убедитесь, что источник и назначение выбраны, после чего нажмите кнопку Finish.

Примечание:
Если нужно, конфигурационный файл можно впоследствии изменить.

Генерация кода

Это не должно вызвать сложностей

  1. Вы уже сделали самую трудную работу, поэтому можете приступить к созданию кода; для этого просто нажмите правой кнопкой мыши на tc1.tc и выберите команды Transform > UML to C++ из контекстного меню. После этого в проекте, который был выбран в качестве назначения при создании конфигурационного файла преобразования, будет сгенерирован нужный код;
  2. Просмотрите код, который был сгенерирован для класса Route. Он содержит атрибуты startingPoint и endingPoint, а также метод getFare() (см. код листинга 1).
Листинг 1. Route.h - код, сгенерированный для класса Route
#ifndef ROUTE_H
#define ROUTE_H
//Начало секции для файла Route.h
//TODO: Добавьте определения, которые должны быть сохранены
//Завершение секции для файла Route.h

struct Address;

//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
class Route
{

    private:
  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_Hk7qMACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
        float runningCost;

	  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_hKd58ACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
        float expectedProfit;

	  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_ieiw8ACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
        Address * startingPoint;

	  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_jkEOkACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
        Address * endingPoint;
    public:

	  //@uml.annotationsderived_abstraction="platform:/resource/UML-1/
DWArticle-1.emx#_kawmAACuEdy9t-_gdCbefQ"
        //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"

        float getFare()const ;

};  //Завершение описания класса Route

#endif

Тело метода getFare по умолчанию было сгенерировано в соответствии с листингом 2.

Листинг 2. Route.cpp
#include "Route.h"
//Начало секции для класса Route.cpp
//TODO: Добавьте определения, которые должны быть сохранены
//Завершение секции для файла Route.cpp


float Route::getFare() const 
{
    //TODO Автоматически сгенеренный метод заглушек
    return 0;
}

Изменение кода

Вы должны были заметить, что тело по умолчанию вряд ли используется часто, потому что тариф всегда равен 0 (нулю). Вряд ли это сделает предприятие выгодным! Поэтому нам придется заменить тело метода getFare кодом, представленным в листинге 3.

Листинг 3. Route.cpp
float Route::getFare() const 
{
    // Расчет тарифа
    return runningCost * expectedProfit;
}

Разработка модели и повторное применение преобразования

Далее, добавим еще один метод с именем print_disclaimer() в класс Route UML-модели.

  1. Укажите тип возврата для метода - String;
  2. Обратите внимание на то, что мы изменили также файл Route.cpp, добавив тело для метода getFare;
  3. Выполните преобразование, воспользовавшись той же конфигурацией преобразования (tc1.tc > Transformation > UML to C++);
  4. Согласитесь с настройками по умолчанию, которые вы увидите в диалоговом окне; они предупреждают о том, что будут обновлены файлы назначения.

После этого изучите обновленный код (Листинг 4).

Листинг 4. Обновленный файл Route.cpp
#include "Route.h"
//Начало секции для файла Route.cpp
//TODO: Добавьте определения, которые должны быть сохранены
//Завершение секции для файла Route.cpp


float Route::getFare() const 
{
    // Расчет тарифа
    return runningCost * expectedProfit;
}

//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
const char * Route::print_disclaimer() 
{
     //TODO Автоматически сгенеренный метод заглушек
    return 0;
}

Обратите внимание, что измененное тело для метода getFare() сохранено. В то же время новый метод print_disclaimer, добавленный в модель, вызвал генерацию нового кода в файлах Route.h и Route.cpp files. Так вы можете продолжать реализовать свои методы в коде и, одновременно, вносить поэтапные изменения в модель. Благодаря этому у вас появляется возможность вести управляемую моделями итеративную разработку.

Добавление пользовательских предложений include в секцию сохраняемого кода

В листинге 5 мы написали код для метода print_disclaimer. Обратите внимание на использование оператора cout. Преобразованию С++ об этом ничего не известно. Однако, чтобы повторное выполнение прошло корректно, важно, чтобы код можно было подвергнуть синтаксическому разбору для сохранения структуры кода и тела методов при повторном выполнении преобразования. Чтобы сделать код компилируемым, необходимо добавить в файл с расширением cpp предложения #include <iostream> и using namespace std. Эти предложения обязательно будут сохранены при повторных выполнениях преобразования UML - C++. Для этого необходимо вставить указанные предложения между комментариями:

//Начало секции для файла Route.cpp
//Завершение секции для файла Route.cpp

Все, что вы добавите в эту секцию, будет сохранено дословно и не будет интерпретироваться преобразованием С++.

Листинг 5. Route.cpp
#include "Route.h"
//Начало секции для файла Route.cpp
#include <iostream>
using namespace std;
//Завершение секции для файла Route.cpp


float Route::getFare() const 
{
    // Расчет тарифа
    return runningCost * expectedProfit;
}

//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
const char * Route::print_disclaimer() 
{
    const char *s = "No Refund once the ticket is purchased\n";
    cout << s;
    return s;
}

Примечание о загружаемых файлах:

  • Примеры UML-модели и проектов C++: данные проекты в виде .zip-архивов можно импортировать в рабочую область Eclipse; для этого необходимо выбрать из меню команды File > Import, а затем вызвать мастер импорта существующих проектов в рабочую область Import Existing Projects into Workspace wizard.

Заключение

В этой статье были продемонстрированы основы использования Rational Systems Developer для создания UML-модели для генерации кода C++ и способы параллельной работы над кодом и моделью. Дополнительную информацию можно найти по ссылкам в разделе Ресурсы.


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Rational
ArticleID=291603
ArticleTitle=Преобразования UML- C++ в IBM Rational Systems Developer и Rational Software Architect
publish-date=02262008