Генерация программного кода
Команды для генерации кода на языке Ada 95 содержит пункт Toots главного меню (рис. 17.33).
1. На компонентной диаграмме выделите оба компонента CourseOffering.
2. Выберите команду Tools:Ada95: Code Generation из главного меню.
Итоги генерации кода отображаются в окне Code Generation Status (рис. 17.34).
Все ошибки заносятся в log-окно.
3. Для завершения процесса генерации кода нажмите кнопку Close.
Рис. 17.33. Меню Tools: генерация кода на языке Ada 95
Рис. 17.34.Статус генерации кода
В процессе генерации Rational Rose отображает логическое описание класса в каркас программного кода — в коде появляются языковые описания имени класса, свойств класса и заголовки методов. Кроме того, для описания тела каждого метода формируется программная заготовка. Появляются и программные связи классов. Подразумевается, что программист будет дополнять этот код, работая в конкретной среде программирования, имеющей мост связи с системой Rational Rose. После каждого существенного дополнения программист с помощью возвратного проектирования, основанного на использовании моста связи, будет модифицировать диаграммы классов, вводя в них изменения, соответствующие результатам программирования.
Просмотрим код, сгенерированный средой Rational Rose.
Фрагмент содержания .ads-файла, отражающего спецификацию класса CourseOffering,представлен на рис. 17.35. Отметим, что в программный текст добавлено то описание, которое было внесено в модель через окно документации. Более того, система Rational Rose подготавливает код к многократной итеративной модификации, защите выполняемых изменений. Стандартный раздел программного кода имеет вид
--##begin module.privateDeclarations preserve=yes
--##end module.privateDeclarations
Рис. 17.35.Код спецификации класса, сгенерированный средой Rational Rose
Запись module.privateDeclarations обозначает имя раздела. Элемент preserve=(yes/no) говорит системе, можно ли при повторной генерации кода этот раздел изменять или нельзя. После генерации кода программный текст добавляется между операторами ##begin и ##end.
Полный листинг сгенерированного кода спецификации выглядит так:
--##begin module.cp preserve=no
--##end module.cp
-- Specification CourseOffering (Package Specification)
-- Dir : C:\Program Files\Rational\Rose\ada95\source
-- File: courseoffering.ads
--##begin module.withs preserve=yes
--##end module.withs
package CourseOffering is
--##begin module.declarations preserve=no
--##end module.declarations
-- Class CourseOffering
-- Documentation:
-- CourseOffering is
-- Concurrency: Sequential
-- Persistence: Transient
-- Cardinality: n
type Object is tagged private;
type Handle is access Object'Class;
-- Array declarations
type Array_0f_0bject is
array (Positive range <>) of Object;
type Access_Array_Of_Object is
access Array_0f_0bject;
-- Standard Operations
function Create return Object;
function Copy (From : in Object) return Object;
procedure Free (This : in out Object);
function Create return Handle;
function Copy (From : in Handle) return Handle;
procedure Free (This : in out Handle);
-- Accessor Operations for Associations
function Get_The_Course (This : in Object)
return Course.Handle;
pragma Inline (Get_The_Course);
-- Association Operations
procedure Associate (This_Handle : in Handle;
This_Handle : in Handle);
procedure Associate (This_Handle : in Handle;
This_Array_Of_Handle : in Array_Of_Handle);
procedure Dissociate (This : in Handle);
procedure Dissociate (This : in Handle);
procedure Dissociate (This : in Array_Of_Handle);
-- Other Operations
function offeringOpen (This : in Object) return Integer;
--##begin module.additionalDeclarations preserve=yes
--##end module.additiona1Declarations
private
--##begin module.privateDeclarations preserve=yes
--##end module.privateDeclarations
type Object is tagged
record
-- Data Members for Class Attributes
numberStudents : Integer;
-- Data Members for Associations
The_Course : Course.Handle;
--##begin CourseOffering.private preserve=no
--##end CourseOffering.private
end record:
--##begin module.additionalPrivateDeclarations preserve=yes
--##end module.additionalPrivateDeclarations
end CourseOffering;
Соответственно, фрагмент содержания .adb-файла, отображающего тело класса CourseOffering, представлен на рис. 17.36.
Рис. 17.36.Код тела класса, сгенерированный Rational Rose
Полный листинг сгенерированного кода для тела класса выглядит следующим образом:
--##begin module.cp preserve=no
--##end module.cp
-- Body CourseOffering (Package Body)
-- Dir : C:\Program Files\Rationa1\Rose\ada95\source
-- File: courseoffering.adb
with Unchecked_Deallocation;
--##begin module.withs preserve=yes
--##end module.withs
package body CourseOffering is
--##begin module.declarations preserve=no
--##end module.declarations
-- Standard Operations
--##begin CourseOffering.CreatefcObject.documentation preserve=yes
--##end CourseOffering.Create%Object.documentation
function Create return Object is
--##begin CourseOffering.Create%Object.declarations preserve=no
--##end CourseOfferi ng.Create%Object.declarations
begin
--##begin CourseOffering.Create%Object.statements preserve=no
[statement]
--##end CourseOffering.Create%Object.statements
end Create;
--##begin CourseOffering.Copy%Object.documentation preserve=yes
--##end CourseOfferi ng.Copy%Object.documentation
function Copy (From : in Object) return Object is
--##begin CourseOffering.Copy%Object.declarations preserve=no
--##end CourseOffering.Copy%Object.declarations
begin
--##begin CourseOffering.Copy%Object.statements preserve=no
[statement]
--##end CourseOfferi ng.Copy%Object.statements
end Copy;
--##begin CourseOffering.Free%Object.documentation preserve=yes
--##end CourseOfferi ng.Free%Object.documentation
procedure Free (This : in out Object) is
--##begin CourseOffering.Free%Object.declarations preserve=yes
--##end CourseOfferi ng.Free%Object.decl arati ons
begin
--##begin CourseOffering.Free%Object.statements preserve=no
[statement]
--##end CourseOffering.Free%Object.statements
end Free;
--##beginCourseOffering. Create%Handle. documentati on preservers=yes
--##end CourseOffering.Create%Handle.documentation
function Create return Handle is
--##begin CourseOffering.Create%Handle.declarations preserve=no
--##end CourseOffering.Create%Handle.declarati ons
begin
--##begin CourseOffering.Create%Handle.statements preserve=no
[statement]
--##end CourseOfferi ng.Create%Handle.statements
end Create;
--##begi n CourseOffering.Copy%Handle.documentation preserve=yes
--##end CourseOffering.Copy%Handle.documentation
function Copy (From : in Handle) return Handle is
--##begin CourseOffering.Copy%Handle.declarations preserve=no
--##end CourseOfferi ng.Copy%Handle.declarations
begin
--##begin CourseOffering.Copy%Handle.statements preserve=no
[statement]
--##end CourseOfferi ng.Copy%Handle.statements
end Copy;
--##begin CourseOffering.Free%Handle.documentation preserve=yes
--##end CourseOfferi ng.Free%Handle.documentation
procedure Free (This : in out Handle) is
--##begin CourseOffering.Free%Handle.declarations preserve=yes
--##end CourseOffering. Free%Handle. declarations
begin
--##begin CourseOf feri ng.Free%Handle. statements preserve=no
[statement]
--##end CourseOffering.Free%Handle.statements
end Free:
-- Other Operations
--##begin CourseOffenng.offeringOpen%Object.940157546.documentati on preserve=yes
--##end CourseOfferi ng.offeringOpen%Object.940157546.documentation
function offeringOpen (This : in Object) return Integer is
--##begin CourseOfferi ng.offeri ngOpen%Object.940157546.declarations preserve=yes
--##end CourseOfferi ng.offeri ngOpen%Object.940157546.declarations
begin
--##begin CourseOfferi ng.offeri ngOpen%Object.940157546.statements preserve=yes
[statement]
--##end CourseOf feri ng. of f eri ngOpen%Object. 940157546. statements
end offeringOpen;
-- Accessor Operations for Associations
--##begin CourseOffering.Get_The_Course%Object.documentati on preserve=yes
--##end CourseOfferi ng. Get_The_Course%Object. documentati on
function Get_The_Course (This : in Object) return Course.Handle is
--##begi n CourseOfferi ng.Get_The_Course%Object.declarati ons preserve=no
--##end CourseOffering. Get__The_Course%Object. declarations
begin
--##begi n CourseOfferi ng.Get_The_Course%Object.statements preserve=no
return This.The_Course;
--##end CourseOfferi ng.Get_The_Course%Object.statements
end Get_Jhe_Course;
-- Association Operations
--##begin module.associations preserve=no
generic
type Role_Type is tagged private;
type Access_Role_Type is access Role_Type'Class;
type Index is range <>;
type Array _Of_Access_Role_Type is
array (Index range <>) of Access_Role_Type;
type Access_Array_Of_Access Role_Type is
access Array_Of_Access_Ro1e_Type;
package Generic_Tagged_Association is
procedure Set (This_Access_Array : in out
Access_Array_Of_Access_Role_Type;
This_Array : Array_Of_Access_Role_Type;
Limit : Positive := Positive
((Index'Last - Index'First) + 1));
function Is_Unique (This_Array : Array_Of_Access_Role_Type;
This : Access_Ro1e_Type) return Boolean;
function Unique (This_Array : in Array_Of_Access_Role_Type)
return Array_Of_Access_Role_Type;
pragma Inline (Set, Is_Unique, Unique);
end Generic_Tagged_Association;
package body Generic_Tagged_Association is
procedure Free is new Unchecked_Deallocation
( Array_Of_Access_Role_Type,
Access_Array_Of_Access_Role_Type);
procedure Set (This_Access_Array : in out
Access_Array_Of_Access_Role_Type;
This_Array : Array_Of_Access_Role_Type;
Limit : Positive := Positive
((Index'Last - Index'First) + 1)) is
Valid : Boolean;
Pos : Index := This_Array'First;
Last : constant Index := This_Array'Last;
Temp_Access_Array : Access_Array_Of_Access_Role_Type;
begin
if Positive(This_Array'Length) > Limit then
raise Constraint_Error;
end if;
if This_Access_Array - null then
-- Allocate entries.
This_Access_Array := new
Array_Of_Access_Role_Type'(This_Array);
return;
end if;
for I in This_Array'Range loop
Valid := Is_Unique (Th1s_Access_Array.all. This_Array (I));
pragma Assert (Valid);
end loop;
-- Reuse any empty slots.
for I in This_Access_Array'Range loop
if This_Access_Array (I) = null then
This_Access_Array (I) := This_Array (Pos);
Pos := Pos + 1;
if Pos > Last then return;
end if;
end if;
end loop;
if Positive(This_Access_Array'Length + (Last - Pos + 1)) > Limit then raise
Constraint_Error;
end if;
-- For any remaining entries, combine by reallocating.
Temp_Access_Array := new Array_Of_Access_Role_Type'
(This_Access_Array.all & This_Array (Pos .. Last));
Free (This_Access_Array);
This_Access_Array := Temp_Access_Array;
end Set;
function Is_Unique (This_Array : Array_Of_Access_Role_Type;
This : Access_Role_Type) return Boolean is
begin
if This = null then return False;
end if;
for I in This_Array'Range loop
if This_Array (I) = This then return False;
end if;
end loop;
return True;
end Is_Unique;
function Unique (This_Array : in Array_Of_Access_Role_Type)
return Array_Of_Access_Ro1e_Type is
First : constant Index := This_Array'First;
Count : Index := First;
Temp_Array : Array_Of_Access_Role_Type (This_Array'Range);
begin
for I in This_Array'Range loop
if Is_Unique (Temp_Array (First .. Count - 1).
This_Array (I)) then
Temp_Array (Count) := This_Array (I);
Count :- Count + 1;
end if;
end loop;
return Temp_Array (First .. Count - 1);
end Unique:
end Generic_Tagged_Association;
package Role_0bject is new Generic_Tagged_Association
(Object,
Handle,
Positive,
Array_Of_Handle,
Access_Array_Of_Hand1e);
--##end module.associations
procedure Associate (This_Handle : in Handle: This_Handle
: in Handle) is
--#begin Associate%38099E7D0190.declarations preserve=no
use Role_0bject;
--##end Associate%38099E7D0190.declarations
begin
--##begin Associate%38Q99E70Q190.statements preserve=no
pragma Assert (This_Hand1e /= null);
pragma Assert (This_Handle /= null);
pragma Assert (This_Handle.The_Course = null or
else This_Handle.The_Course = This_Handle);
This_Handle.The_Course := This_Handle;
Set (This_Handle.The_CourseOffering. Array_Of_Handle'(1 =>
This_Handle));
--##end Associate3%38099E7D0l90. statements
end Associate;
procedure Associate (This_Handle : in Handle;
This_Array_Of_Handle : in Array_Of_Handle) is
--##begin Associate%(1,N)38099E7D0190.declarations preserve=no
use Role_0bject;
Temp_Array_Of_Handle : constant Array_Of_Handle := Unique
(This_Array_Of_Handle):
--«end Associate%(l,N)38099E7D0190.declarations
begin
--##begin Associate%(l.N)38099E7D0190.statements preserve=no
pragma Assert (This_Handle /= null);
pragma Assert (Temp_Array_Of_Handle'Length > 0);
for I in Temp_Array_Of_Handle'Range loop
pragma Assert (Temp_Array_Of_Handle (I).The_Course = null or else
Temp_Array_Of_Handle (I).The_Course - This_Handle);
Temp_Array_Of_Handle (I).The_Course := This_Handle;
end loop;
Set (This_Handle.The_CourseOffering. Temp_Array_Of_Handle);
--##end Associate%(1,N)38099E7D0190.statements
end Associate;
procedure Dissociate (This : in Handle) is
--##begin Dissociate«38099E7D0190.declarations preserve=yes
--##end Dissociate«38099E7D0190.declarations
begin
--##begin Dissociate%38099E7D0190.statements preserve=no
pragma Assert (This /= null);
for I in This.The_CourseOffering'Range loop
if This.The_CourseOffering (I) /= null then
if This.The_CourseOffering (I).The_Course = This then
This.The_CourseOffering (I).The_Course := null;
This.The_CourseOffering (I) := null;
end if;
end if;
end loop;
--##end Dissociate%38099E7D0190.statements
end Dissociate;
procedure Dissociate (This := in Handle) is
--##begin Dissociate%38099E7D0190.declarations preserve=yes
--##end Dissociate%38099E7D0190.declarations
begin
--##begin Dissociate%38099E7D0190.statements preserve=no
pragma Assert (This /= null):
for I in This.The_Course.The_CourseOffering'Range loop
if This.The_Course.The_CourseOffering (I) = This then
This.The_Course.The_CourseOffering (I) :=null;
This.The_Course ;=null;
exit:
end if;
end loop;
--##end Dissociat%38099E7D0190.statements
end Dissociate;
procedure Dissociate (This : in Array_Of_Handle) is
--##begin Dissociate%(M)38099E7D0190.declarations preserve=yes
--##end Dissociate%(M)38099E7D0190.declarations
begin
--##begin Dissociate%(M)38099E7D0190.statements preserve=no
for I in This'Range loop
if This (I) /= null then
Dissociate (This (I));
end if;
end loop;
--##end Dissociate%(M)38099E7D0190.statements
end Dissociate;
--##begin module.additionalDeclarations preserve=yes
--##end module.additionalDec!arations
begin
--##begin module.statements preserve=no
null;
--##end module.statements
end CourseOffering;
Отметим, что в теле есть стандартные методы, которые не задавались в модели, — например, методы constructor, destructor и get/set. Их автоматическая генерация была задана настройкой среды — свойствами генерации. Система обеспечивает настройку параметров генерации для уровней класса, роли, свойства (атрибута) и проекта в целом. Более подробную информацию о свойствах генерации кода можно получить из help-файла.
Заключение
Современная программная инженерия (Software Engineering) — молодая и быстро развивающаяся область знаний и практик. Она ориентирована на комплексное решение задач, связанных с разработкой особой разновидности сложных систем — программных систем.
Программные системы — самые необычные и удивительные создания рук человеческих. Они не имеют физических тел, их нельзя потрогать, ощутить одним из человеческих чувств. Они не подвергаются физическому износу, их нельзя изготовить в обычном инженерном смысле, как автомобиль на заводе. И вместе с тем разработка программных систем является самой сложной из задач, которые приходилось когда-либо решать человеку-инженеру. В пределе — это задача создания рукотворной системы, сопоставимой по сложности самому творцу.
Многие стереотипы и приемы, разработанные в физическом мире, оказались неприменимы к инженерии программных систем. Приходилось многое изобретать и придумывать. Все это теперь история. Программные инженеры начинали с полного неприятия инструментария других инженерных дисциплин, уверовав в свою кастовость «жрецов в белых халатах», и совершили эволюционный круг, вернувшись в лоно общечеловеческой инженерии.
Впрочем, были времена, когда и другие «кланы» людей относились к «программе-рам» с большим подозрением: им мало платили, унижая материально, не находили для них ласковых слов (а употребляли большей частью ругательные). Где эти люди? И где их прежнее отношение?
Современное общество впадает во все большую зависимость от программных технологий. Программного инженера стали любить, охотно приглашать в гости, хорошо кормить, обувать и одевать. Словом, стали лелеять и холить (правда, время от времени продолжают сжигать на костре и предавать анафеме).
Современная программная инженерия почти достигла уровня зрелости — об этом свидетельствуют современные тенденции; она разворачивается от сердитого отношения к своим разработчикам к дружелюбному, снисходительному пониманию человеческих слабостей.
Базис современной программной инженерии образуют следующие составляющие:
q процессы конструирования ПО;
q метрический аппарат, обеспечивающий измерения процессов и продуктов;
q аппарат формирования исходных требований к разработкам;
q аппарат анализа и проектирования ПО;
q аппарат визуального моделирования ПО;
q аппарат тестирования программных продуктов.
Все эти составляющие рассмотрены в данном учебнике. Конечно, многое осталось за кадром. Реорганизация (рефакторинг), особенности конструирования web-приложений, работа с базами данных — вот неполный перечень тем, обсудить которые не позволили ресурсные ограничения. Хотелось бы обратить внимание на новейшие постобъектные методологии — аспектно-ориентированное и многомерное проектирование и программирование. Они представляют собой новую высоту в стремительном полете в компьютерный космос. Но это — тема следующей работы. Впереди длинная и интересная дорога познаний. Как хочется подольше шагать по этой дороге.
В заключение «родился теплый лирический тост» — за программистов всех стран! А если серьезно, друзья, вы — строители целого виртуального мира, я верю в вас, я горжусь вами. Дерзайте, творите, разочаровывайтесь и очаровывайтесь! Я уверен, вы построите достойное информационное обеспечение человеческого общества!
Приложение А.