|
| ||||||||||||
| ||||||||||||
|
2000 г
Rose для разработчиков и ради разработчиков. Часть 3© Новичков А.Н. "Семь раз исправь, - десять отладь:" - ОбщееВ прошлых частях мы достаточно много времени уделили такому мощному инструменту, как Rational Rose, причем старались разглядеть данный продукт глазами разработчика (постановщика). Достаточно подробно рассмотрели процесс проектирования как прямого, так и обратного на языке С++. Естественно, что не удалось покрыть полностью все возможности пакета, так как в этом случае пришлось бы писать целую книгу. К сожалению, во время написания третьей части данной статьи (такой же описательной как и все предыдущие) вышла в свет на русском языке великолепная книга по проектированию и кодогенерации ("UML и Rational Rose". У. Боггс, М. Боггс.). Стало быть 3 часть будет последней описательной частью: Остальные части планируются уже не в описательном формате, а в проблематичном каждая статья берет за основу конкретную проблему проектирования или анализа, а также взаимодействия Rational Rose с другими продуктами компании Rational. Например, в одной из ближайших частей мы затронем интеграцию Rose с ClearCase и Requisite Pro. Также ждет своего череда статья по интеграции с Visual Studio. Сложные материи.Здесь мы уже не будем так дотошно проводить кодогенерацию, как в предыдущих частях. Основной упор будет поставлен на изобразительные возможности инструмента при моделировании, так как функция наследования (вещь сама по себе очень интересная) достаточно банальна сама по себе и не требует особого понимания и подхода. Простая вещь - простое действие. Давайте попробуем затронуть более сложные манипуляции с классами. Давайте для начала вкратце проанализируем возможности Rational Rose в генерации и визуализации различных ассоциаций, связей и классов.
Однонаправленные ассоциацииДля создания подобной связи Rose генерирует специальные атрибуты. Естественно, что при подобной ассоциации связь генерируется только для одного класса. При этом Rose генерирует закрытый атрибут (Private). В остальном генерация происходит так же как и в наследовании (связь показывается стрелкой Unidirectional Association). Ниже показана картинка отношения и код, сгенерированный Rose (далее в статье также будет использоваться такой же подход: описание связи, рисунок связи, сгенерированный файл заголовка).
Рис.1 ФАЙЛ NEWSTRING.H
//## 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%39FD296801A9.cm preserve=no
// %X% %Q% %Z% %W%
//## end module%39FD296801A9.cm
//## begin module%39FD296801A9.cp preserve=no
//## end module%39FD296801A9.cp
//## Module: NewString%39FD296801A9; Pseudo Package specification
//## Source file: C:\Program Files\Rational2\Rose\C++\source\NewString.h
#ifndef NewString_h
#define NewString_h 1
//## begin module%39FD296801A9.additionalIncludes preserve=no
//## end module%39FD296801A9.additionalIncludes
//## begin module%39FD296801A9.includes preserve=yes
//## end module%39FD296801A9.includes
// String
#include "String.h"
//## begin module%39FD296801A9.additionalDeclarations preserve=yes
//## end module%39FD296801A9.additionalDeclarations
//## begin NewString%39FD296801A9.preface preserve=yes
//## end NewString%39FD296801A9.preface
//## Class: NewString%39FD296801A9
//## Category: <Top Level>
//## Persistence: Transient
//## Cardinality/Multiplicity: n
class NewString
{
//## begin NewString%39FD296801A9.initialDeclarations preserve=yes
//## end NewString%39FD296801A9.initialDeclarations
public:
//## Constructors (generated)
NewString();
NewString(const NewString &right);
//## Destructor (generated)
~NewString();
//## Assignment Operation (generated)
NewString & operator=(const NewString &right);
//## Equality Operations (generated)
int operator==(const NewString &right) const;
int operator!=(const NewString &right) const;
//## Get and Set Operations for Associations (generated)
//## Association: <unnamed>%39FD2A2602A7
//## Role: NewString::<the_String>%39FD2A270212
const String * get_the_String () const;
void set_the_String (String * value);
// Additional Public Declarations
//## begin NewString%39FD296801A9.public preserve=yes
//## end NewString%39FD296801A9.public
protected:
// Additional Protected Declarations
//## begin NewString%39FD296801A9.protected preserve=yes
//## end NewString%39FD296801A9.protected
private:
// Additional Private Declarations
//## begin NewString%39FD296801A9.private preserve=yes
//## end NewString%39FD296801A9.private
private: //## implementation
// Data Members for Associations
//## Association: <unnamed>%39FD2A2602A7
//## begin NewString::<the_String>%39FD2A270212.role preserve=no public: String { -> RHN}
String *the_String;
//## end NewString::<the_String>%39FD2A270212.role
// Additional Implementation Declarations
//## begin NewString%39FD296801A9.implementation preserve=yes
//## end NewString%39FD296801A9.implementation
};
//## begin NewString%39FD296801A9.postscript preserve=yes
//## end NewString%39FD296801A9.postscript
// Class NewString
//## Get and Set Operations for Associations (inline)
inline const String * NewString::get_the_String () const
{
//## begin NewString::get_the_String%39FD2A270212.get preserve=no
return the_String;
//## end NewString::get_the_String%39FD2A270212.get
}
inline void NewString::set_the_String (String * value)
{
//## begin NewString::set_the_String%39FD2A270212.set preserve=no
the_String = value;
//## end NewString::set_the_String%39FD2A270212.set
}
//## begin module%39FD296801A9.epilog preserve=yes
//## end module%39FD296801A9.epilog
#endif
Двунаправленные ассоциацииЭто усложненный аналог предыдущей связи, во время исполнения которой генерируются ссылки на оба используемых класса. Визуально ассоциация показывается простой линией Association.
Рис.2 Ниже показаны только фрагменты двух классов, с упором на сгенерированную ассоциацию. ФАЙЛ STRING.h
*
*
*
private: //## implementation
// Data Members for Associations
//## Association: <unnamed>%39FD2E8E00AA
//## begin String::<the_NewString>%39FD2E8E0399.role preserve=no public: NewString { -> RHN}
NewString *the_NewString;
//## end String::<the_NewString>%39FD2E8E0399.role
// Additional Implementation Declarations
//## begin String%39FD295103B9.implementation preserve=yes
//## end String%39FD295103B9.implementation
*
*
*
ФАЙЛ NEWSTRING.h
*
*
*
private: //## implementation
// Data Members for Associations
//## Association: <unnamed>%39FD2E8E00AA
//## begin NewString::<the_String>%39FD2E8E03A3.role preserve=no public: String { -> RHN}
String *the_String;
//## end NewString::<the_String>%39FD2E8E03A3.role
// Additional Implementation Declarations
//## begin NewString%39FD296801A9.implementation preserve=yes
//## end NewString%39FD296801A9.implementation
*
*
*
Ассоциация "один ко многим"Данный вид ассоциаций также представляет особую ценность при проектировании классов. Множественность ассоциации задается в свойствах связи (пункты Role A Detail и Role B Detail. Где помимо ролей можно задать и специфические атрибуты конкретной ассоциациии, ну, скажем, дать ей название. Рис. 3 показывает скриншот данного окна). Рисунок 4, в свою очередь, демонстрирует внешний вид данной ассоциации.
Рис.3
Рис.4 ФАЙЛ STRING.h
*
*
*
private: //## implementation
// Data Members for Associations
//## Association: <unnamed>%39FD300C00A9
//## begin String::<the_NewString>%39FD300C033E.role preserve=no public: NewString {n -> 1RHN}
NewString *the_NewString;
//## end String::<the_NewString>%39FD300C033E.role
// Additional Implementation Declarations
//## begin String%39FD295103B9.implementation preserve=yes
//## end String%39FD295103B9.implementation
*
*
*
ФАЙЛ NEWSTRING.h
*
*
*
private: //## implementation
// Data Members for Associations
//## Association: <unnamed>%39FD300C00A9
//## begin NewString::<the_String>%39FD300C0348.role preserve=no public: String {1 -> nRHN}
UnboundedSetByReference<String> the_String;
//## end NewString::<the_String>%39FD300C0348.role
// Additional Implementation Declarations
//## begin NewString%39FD296801A9.implementation preserve=yes
//## end NewString%39FD296801A9.implementation
*
*
*
Как видно из фрагментов кода, мы получили, как и впредыдущих случаях, ссылку на класс, в то то время, как для другого класса был использован контейнер. По умолчанию Rational Rose не предоставляет реализацию контейнерного класса. Вместо него генерируется код с UnboundedSetByReference в качестве контейнерного. Указание же конкретного контейнерного класса - дело самого разработчика. Связь "многие ко многим"Данный пример практически аналогичен предыдущему, с той лишь разницей, что, генерируется двойная связь: контейнерные классы на обоих концах. Ассоциации с ограниченной множественностьюДанный вид ассоциаций представляет логическое продолжение предыдущего типа ассоциаций, но в отличие от него имеет строго ограниченное количество связей (ограничение по диапазону). Рисунок 5 показывает модель подобного взаимоотношения классов
Рис.5 Код получается следующим: ФАЙЛ STRING.h
//## 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%39FD295103B9.cm preserve=no
// %X% %Q% %Z% %W%
//## end module%39FD295103B9.cm
//## begin module%39FD295103B9.cp preserve=no
//## end module%39FD295103B9.cp
//## Module: String%39FD295103B9; Pseudo Package specification
//## Source file: C:\Program Files\Rational2\Rose\C++\source\String.h
#ifndef String_h
#define String_h 1
//## begin module%39FD295103B9.additionalIncludes preserve=no
//## end module%39FD295103B9.additionalIncludes
//## begin module%39FD295103B9.includes preserve=yes
//## end module%39FD295103B9.includes
// NewString
#include "NewString.h"
//## begin module%39FD295103B9.additionalDeclarations preserve=yes
//## end module%39FD295103B9.additionalDeclarations
//## begin String%39FD295103B9.preface preserve=yes
//## end String%39FD295103B9.preface
//## Class: String%39FD295103B9
//## Category: <Top Level>
//## Persistence: Transient
//## Cardinality/Multiplicity: 1
class String
{
//## begin String%39FD295103B9.initialDeclarations preserve=yes
//## end String%39FD295103B9.initialDeclarations
public:
//## Constructors (generated)
String();
String(const String &right);
//## Destructor (generated)
~String();
//## Assignment Operation (generated)
String & operator=(const String &right);
//## Equality Operations (generated)
int operator==(const String &right) const;
int operator!=(const String &right) const;
//## Get and Set Operations for Associations (generated)
//## Association: <unnamed>%39FD300C00A9
//## Role: String::<the_NewString>%39FD300C033E
const NewString * get_the_NewString () const;
void set_the_NewString (NewString * value);
// Additional Public Declarations
//## begin String%39FD295103B9.public preserve=yes
//## end String%39FD295103B9.public
protected:
// Additional Protected Declarations
//## begin String%39FD295103B9.protected preserve=yes
//## end String%39FD295103B9.protected
private:
// Additional Private Declarations
//## begin String%39FD295103B9.private preserve=yes
//## end String%39FD295103B9.private
private: //## implementation
// Data Members for Associations
//## Association: <unnamed>%39FD300C00A9
//## begin String::<the_NewString>%39FD300C033E.role preserve=no public: NewString {n -> 1RHN}
NewString *the_NewString;
//## end String::<the_NewString>%39FD300C033E.role
// Additional Implementation Declarations
//## begin String%39FD295103B9.implementation preserve=yes
//## end String%39FD295103B9.implementation
};
//## begin String%39FD295103B9.postscript preserve=yes
//## end String%39FD295103B9.postscript
// Class String
//## Get and Set Operations for Associations (inline)
inline const NewString * String::get_the_NewString () const
{
//## begin String::get_the_NewString%39FD300C033E.get preserve=no
return the_NewString;
//## end String::get_the_NewString%39FD300C033E.get
}
inline void String::set_the_NewString (NewString * value)
{
//## begin String::set_the_NewString%39FD300C033E.set preserve=no
the_NewString = value;
//## end String::set_the_NewString%39FD300C033E.set
}
//## begin module%39FD295103B9.epilog preserve=yes
//## end module%39FD295103B9.epilog
#endif
ФАЙЛ NEWSTRING.h
//## 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%39FD296801A9.cm preserve=no
// %X% %Q% %Z% %W%
//## end module%39FD296801A9.cm
//## begin module%39FD296801A9.cp preserve=no
//## end module%39FD296801A9.cp
//## Module: NewString%39FD296801A9; Pseudo Package specification
//## Source file: C:\Program Files\Rational2\Rose\C++\source\NewString.h
#ifndef NewString_h
#define NewString_h 1
//## begin module%39FD296801A9.additionalIncludes preserve=no
//## end module%39FD296801A9.additionalIncludes
//## begin module%39FD296801A9.includes preserve=yes
//## end module%39FD296801A9.includes
// String
#include "String.h"
//## begin module%39FD296801A9.additionalDeclarations preserve=yes
//## end module%39FD296801A9.additionalDeclarations
//## begin NewString%39FD296801A9.preface preserve=yes
//## end NewString%39FD296801A9.preface
//## Class: NewString%39FD296801A9
//## Category: <Top Level>
//## Persistence: Transient
//## Cardinality/Multiplicity: n
class NewString
{
//## begin NewString%39FD296801A9.initialDeclarations preserve=yes
//## end NewString%39FD296801A9.initialDeclarations
public:
//## Constructors (generated)
NewString();
NewString(const NewString &right);
//## Destructor (generated)
~NewString();
//## Assignment Operation (generated)
NewString & operator=(const NewString &right);
//## Equality Operations (generated)
int operator==(const NewString &right) const;
int operator!=(const NewString &right) const;
//## Get and Set Operations for Associations (generated)
//## Association: <unnamed>%39FD300C00A9
//## Role: NewString::<the_String>%39FD300C0348
const UnboundedSetByReference<String> get_the_String () const;
void set_the_String (UnboundedSetByReference<String> value);
// Additional Public Declarations
//## begin NewString%39FD296801A9.public preserve=yes
//## end NewString%39FD296801A9.public
protected:
// Additional Protected Declarations
//## begin NewString%39FD296801A9.protected preserve=yes
//## end NewString%39FD296801A9.protected
private:
// Additional Private Declarations
//## begin NewString%39FD296801A9.private preserve=yes
//## end NewString%39FD296801A9.private
private: //## implementation
// Data Members for Associations
//## Association: <unnamed>%39FD300C00A9
//## begin NewString::<the_String>%39FD300C0348.role preserve=no public: String {1 -> nRHN}
UnboundedSetByReference<String> the_String;
//## end NewString::<the_String>%39FD300C0348.role
// Additional Implementation Declarations
//## begin NewString%39FD296801A9.implementation preserve=yes
//## end NewString%39FD296801A9.implementation
};
//## begin NewString%39FD296801A9.postscript preserve=yes
//## end NewString%39FD296801A9.postscript
// Class NewString
//## Get and Set Operations for Associations (inline)
inline const UnboundedSetByReference<String> New-String::get_the_String () const
{
//## begin NewString::get_the_String%39FD300C0348.get preserve=no
return the_String;
//## end NewString::get_the_String%39FD300C0348.get
}
inline void NewString::set_the_String (UnboundedSetByReference<String> value)
{
//## begin NewString::set_the_String%39FD300C0348.set preserve=no
the_String = value;
//## end NewString::set_the_String%39FD300C0348.set
}
//## begin module%39FD296801A9.epilog preserve=yes
//## end module%39FD296801A9.epilog
#endif
Код специально приведен полностью, чтобы можно было бы оценить размах Rose в плане генерации сложных связей. Лаконичным завершение данного вида связи можно считать связь один к:. В нашем случае 1 к 6
Рис.6 При этом код будет выглядеть следующим образом ФАЙЛ NEWSTRING.h
*
*
*
private: //## implementation
// Data Members for Associations
//## Association: <unnamed>%39FD4614028A
//## begin NewString::<the_String>%39FD461502A0.role preserve=no public: String {1 -> 6RHN}
String *the_String[6];
//## end NewString::<the_String>%39FD461502A0.role
// Additional Implementation Declarations
//## begin NewString%39FD296801A9.implementation preserve=yes
//## end NewString%39FD296801A9.implementation
*
*
*
Таким же образом можно сгенерировать любой вид связи. Скажем, разработчику ничего не мешает определить связь 6 к 6 или 10 к 10. Код, сгенерированный системой, при этом будет выглядеть как "положено": ЗаключениеПри кодогенерации следует учитывать одно "но". Все что происходит по умолчанию не всегда может устроить конкретного раработчика. Даже учитывая то, что инструмент изначально настроен на генерацию правильного и качественного кода, все равно Rose требует дополнительной подстройки под конкретный проект (релиз.. и пр.) Мощные выразительные свойства в Rational Rose сочетаются с гибкой системой подсказок и настроек. Так, например, Rose позволяет проводить не только простую настройку инструментальной панели (Это возможность стала давно тривиальной, и рассматривать ее как нечто выдающееся нет необходимости), но и что очень важно - настраивать по своему усмотрению внешний вид диаграмм, для которых отсутствует картинка. Внутренне устроение Rose позволяет менять системный файл "defaultstereotypes.ini", в котором содержатся наименования предопределенных стереотипов со ссылками на соответствующие картинки. Так если пользователя не устраивает картинка, то он спокойно может заме-нить ссылку на свой графический файла. Правда при этом следует учитывать, что все рисунки должны храниться только в формате WMF, и иметь длину не более 512 байт. АнонсВ следующей части статьи мы рассмотрим
См. также:
|
|
CITForum © 1997–2025