Генерация исходных текстов программ

Все разработчики сталкиваются с ситуацией, когда приходится проек­тировать большие классы. При ручном вводе и объявлении имеется ряд подводных камней: во-первых, постановщик задач, как правило, описывает «что нужно» на словах, в крайнем случае с минимальным бумажным сопровождением; во-вторых, разработчик, создающий систему, опять-таки в большинстве случаев игнорирует все комментарии, которыми необходи­мо сопровождать программный код. Система кодогенерации Rational Rose позволяет, наряду с другими средствами проектирования, построить про­цесс разработки программного обеспечения как производственный процесс со строгим распределением ролей, полномочий и т. д.

Для демонстрационных целей достаточно спроектировать только один класс. Назовем его String. В его обязанности должны входить основные операции над массивами (печать, копирование, сравнение, получение размера). В качестве примера опишем сначала данный класс на C++:

Class String Protected{
Char *TmpString; Public:
Int Counter;
Int Stat;
Int GetStringSize(Char *);
Int PrintString(Char *);
Int CmpString(Char *, Char *);
Int CpyString(Char *, Char *);
};
 

Теперь средствами Rose все спроектируем в графическом виде. Каждый атрибут задается отдельно, с комментарием, и расписывается тип (public, protected, private). На рис. 15.1 показан разворот спецификации для TmpString. Подобным образом расписываются все переменные.

15-1.jpg (29248 bytes)

Рис 15.1. Разворот спецификации для TmpString

В плане описания функций все аналогично, только помимо описания самой функции (тип возвращаемого значения) необходимо расписать спе­цифику каждого входного параметра, снабдив все это подробнейшими ком­ментариями. Во всех продуктах компании Rational принято давать коммен­тарии для любой малозаметной операции, поскольку впоследствии, при генерации отчетов не нужно будет еще раз вручную доводить документ, чтобы показать его руководству или передать разработчику в качестве технического задания.

Результатом выполнения вышеописанных действий будет появление класса с расписанными спецификациями. Сам класс показан на рис. 15.2. Можно отметить, что в графическом виде можно оценить основные свойства каждого элемента.

15-2.jpg (12475 bytes)
Рис 15.2 Класс String

Следующий шаг в работе - получение кода на C++. Rational Rose 98 в принципе не может дать готового кода, она способна лишь спроектировать класс и расписать спецификацию каждого элемента, подставить шаблоны членов класса для дальнейшего заполнения кодом. Для 100 %-ной генерации рабочего кода на C++ используется Rational Rose RealTime, которая в данном случае не рассматривается.

Рассмотрим кодогенерация (точнее сказать, классогенерацию). Через систему меню выбираем поддерживаемый язык для описания спроектированного класса (в данном случае это C++), вызываем Code Generational. Результатом работы будет появление двух файлов:MyString и MyString. В первом расписывается сам класс, а второй является шаблоном для дальнейшего заполнения соответствующим кодом. Имея подобный шаблон, становится не важно, какой именно разработчик начал создавать кодирование логики класса.Для получения же подробного отчета по классу или технического задания можно воспользоваться инструментом Rational SoDA.

Следующая задача, с которой поможет справиться RationalRose - анализ существующей системы. Зачем переписывать и документировать крупные системы заново, если можно воспользоваться функцией обратно­го проектирования, что позволит из имеющегося кода построить визуаль­ную модель и уже визуально дописать необходимые свойства и атрибуты, дописать новые классы. А под конец сгенерировать весь спектр файлов, необходимых для дальнейшей работы программистов. Данный подход называется Round Trip и полностью поддерживается в RationalRose. 

Файл MyString.h
//
##<em> </em>begin module%1.3%.codegen_version preserve=yes 
// Read the documentation to learn more about C++ code generator versioning.
//## end module%1.3%.codegen_version
//## begin module%395AF70D0321.cm preserve=no
// %X% %Q% %Z% %W%
//## end module%395AF70D0321.cm
//## begin module%395AF70D0321.cp preserve=no 
//## end module%395AF70D0321.cp
//## Module: MyString%395AF70D0321; Pseudo Package specification 
//## Source file: C: \Program Files\Rational\Rose\C++ \source\MyString.h
#ifndef MyString_h 
#defme MyString_h 1
//## begin module%395AF70D0321.additionalIncludes preserve=no 
//## end module%395AF70D0321.additionalIncludes
//## begin module%395AF70D0321.includes preserve=yes
<em>//## </em>end module%395AF70D0321.includes
<em>//## </em>begin module%395AF70D0321.additionalDeclarations preserve=yes 
<em>//## </em>end module%395AF70D0321.additionalDeclarations
//## begin MyString%395AF70D0321.preface preserve=yes
 
//##<em> </em>end MyString%395AF70D0321.preface
<em>//## </em>Class: MyString%395AF70D0321
// Данный класс позволяет проводить различные операции
// над массивами символов.
//## Category: <Top Level>
//## Persistence: Transient
//## Cardinality/Multiplicity: n
class MyString
{
<em>//## </em>begin MyString%395AF70D0321.initialDeclarations preserve=yes
//## end MyString%395AF70D0321.initialDeclarations
public:
//## Constructors (generated)
MyStringQ;
//## Destructor (generated)
~MyString();
//
## Assignment Operation (generated) 
MyString &amp;; operator=(const MyString &amp;right);
//
## Equality Operations (generated)
int operator==(const MyString &amp;right) const;
int operator!=(const MyString &amp;right) const;
//## Other Operations (specified)
//## Operation: GetStringSize%395AF87900E9
// Подсчитывает количество символов в переданном массиве
Int GetStringSize (Char *massiv // Указатель на массив
);
//## Operation: PrintString%395AF88800B9
// Печатает на экране переданный массив
Int PrintString (Char *Massiv // Указатель на массив
);
//## Operation: CmpString%395AF892013F
// Сравнивает два массива.
Int CmpString (Char *Strl, // Указатель на первый массив
Char *Str2 // Указатель на второй массив
);
//## Operation: CpyString%395AF89COOD5 
// Копирует один массив в другой Int CpyString (Char *Dest, 
// Назначение Char * Source // Источник
);
//## Get and Set Operations for Class Attributes (generated)
//## Attribute: Stat%395AF8BB0289
// Общедоступная переменная числа обращений к PrintString
const Int get_Stat () const;
void set_Stat (Int value);
//## Attribute: Count%395AF8C20148
// Определяет статус определенного объекта
const Int get_Count () const;
void set_Count (Int value);
// Additional Public Declarations
<em>//## </em>begin MyString%395AF70D0321.public preserve=yes
//## end MyString%395AF70D0321.public
protected:
// Additional Protected Declarations
//## begin MyString%395AF70D0321.protected preserve=yes
//## end MyString%395AF70D0321.protected
private:
//## Get and Set Operations for Class Attributes (generated)
//## Attribute: TmpString%395AF8B201E5
// Временный указатель на строковый массив. Можно использовать
в качестве буфера
const Char * get_TmpString () const;
void set_TmpString (Char * value);
// Additional Private Declarations
//## begin MyString%395AF70D0321.private preserve
=yes
//## end MyString%395AF70D0321.private
private:
//## implementation
// Data Members for Class Attributes
//## begin MyStrmg::TmpString%395AF8B201E5.attr preserve=no
// private: Char * U Char *TmpString;
//## end MyString::TmpString%395AF8B201E5.attr
//## begin MyString::Stat%395AF8BB0289.attr preserve=no public: Int U
Int Stat;
//## end MyString::Stat%395AF8BB0289.attr
//## begin MyString::Count%395AF8C20148.attr preserve=no public: Int U
Int Count;
//## end MyString::Count%395AF8C20148.attr
// Additional Implementation Declarations
//## begin MyString%395AF70D0321.implementation preserve=yes
//## end MyString%395AF70D0321.implementation
};
//## begin MyString%395AF70D0321.postscript preserve=yes
//## end MyString%395AF70D0321.postscrip
t
// Class MyString
//
## Get and Set Operations for Class Attributes (inline)
inline const Char * MyString::get_TmpString () const
{
//## begin MyString::get_TmpString%395AF8B201E5.get preserve=no
return TmpString;
//## end MyString::get_TmpString%395AF8B201E5.get
}
inline void MyString::set_TmpString (Char * value)
{
//## begin MyString::set_TmpString%395AF8B201E5.set preserve=no
TmpString = value;
//## end MyString::set_TmpString%395AF8B201E5.set
}
inline const Int MyString::get_Stat () const
{
//## begin MyString::get_Stat%395AF8BB0289.get preserve=no
return Stat;
//## end MyString::get_Stat%395AF8BB0289.get }
inline void MyString::set_Stat (Int value)
{
//## begin MyString::set_Stat%395AF8BB0289.set preserve=no
Stat = value;
//## end MyString::set_Stat%395AF8BB0289.set }
inline const Int MyString::get_Count () const
{
//## begin MyString::get_Count%395AF8C20148.get preserve=no
return Count;
//## end MyString::get_Count%395AF8C20148.get
}
inline void MyString::set_Count (Int value)
{
//## begin MyString::set_Count%395AF8C20148.set preserve=no
Count = value;
//## end MyString::set_Count%395AF8C20148.set
}
//## begin module%395AF70D0321.epilog preserve=yes //## end module%395AF70D0321.epilog
#endif

Контрольные вопросы

1. Каковы преимущества автоматической кодогенерации?

2. Какие виды диаграмм используются для генерации кода?

3. Какие компоненты исходного кода генерирует Rational Rose?
4. Как в исходном коде отражаются атрибуты и операции класса?
5. Почему важно детально комментировать компоненты модели?