oldi

BOLD – инструмент реализации MDA в Delphi

Часть 2. Создание простого MDA-приложения

Константин Грибачев

Создание бизнес-уровня

Создание модели приложения

Создание графического интерфейса

Создание уровня данных

Работа с приложением

Модификация модели приложения

Подведение итогов

Резюме

Создание бизнес-уровня

Чтобы быстро ознакомиться с возможностями новой технологии, давайте на практике посмотрим, как создается MDA-приложение с использованием Bold for Delphi. Для этого создадим отдельную папку для нового проекта Delphi. Создадим новый проект в Delphi, состоящий из одной формы, и сохраним его в указанной папке. Пусть для простоты он будет сохранен с именем по умолчанию project1.dpr, а модуль — с именем по умолчанию unit1.pas.

На панели компонентов Delphi выберем закладку <BoldHandles>. Поместим на форму следующие три компонента с закладки <BoldHandles>:

  • BoldModel1 (компонент, обеспечивающий хранение модели);
  • BoldSystemHandle1 (основной компонент — описатель объектного пространства);
  • BoldSystemTypeInfoHandle1 (основной компонент — описатель типов модели).

Эти компоненты реализуют основу объектного пространства (Object Space) нашего приложения. Чтобы правильно функционировать, они должны быть связаны между собой и настроены так, как это будет описано ниже.

Для компонента BoldSystemTypeInfoHandle1 в инспекторе объектов следует установить свойство BoldModel равным BoldModel1 (оно появится в выпадающем списке). Кроме того, установим свойство UseGeneratedCod равным False (рис. 1). Такая установка означает, что генерация кода для классов модели производиться не будет.

Для компонента BoldSystemHandle1 в инспекторе объектов установим свойство SystemTypeInfoHandle равным BoldSystemTypeInfoHandle1 (оно также появится в выпадающем списке). А свойство AutoActivate установим равным True (рис. 2). Таким образом обеспечивается активизация объектного пространства по первому требованию.

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

В начало В начало

Создание модели приложения

Для создания модели в нашем примере мы будем использовать встроенный в Bold for Delphi редактор моделей. Для перехода в редактор кликните дважды на компоненте BoldModel1, расположенном на нашей форме, или правой кнопкой мыши на этом компоненте вызовите всплывающее меню и перейдите на его первый пункт Open Bold UML Editor. Вы увидите окно встроенного редактора UML (рис. 3), позволяющего создавать UML-модели (в текстовом режиме), а также обеспечивающего реализацию основных функциональных возможностей Bold на этапе разработки приложения — таких как экспорт и импорт моделей из других редакторов, модификация, верификация и тонкая настройка моделей, генерация баз данных и кода. На настоящем этапе мы используем его для создания модели нашего простого приложения.

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

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

Таким образом, после некоторой дальнейшей конкретизации неформально будущую модель приложения можно описать следующим набором бизнес-правил:

  • описываемая предметная область включает множество авторов и множество книг;
  • автор однозначно идентифицируется текстовым атрибутом — именем;
  • книга однозначно описывается текстовым атрибутом — названием;
  • автор может написать много книг;
  • книга может быть написана только одним автором.

Назначение UML-редактора — преобразовать неформальное описание бизнес-правил в формальную модель на языке UML (рис. 3).

Теперь можно приступить к созданию модели. Правой кнопкой мыши кликнем на пункте LogicalView в верхней части левой панели редактора и во всплывающем меню выберем пункт NewClass (создание нового класса). Проделаем эту операцию еще два раза (рис. 4).

Новые классы по умолчанию получили имена NewClass, NewClass_1, NewClass_2. Для удобства дальнейшей работы переименуем их. Для этого в левой панели редактора выберем курсором мыши пункт NewClass, перейдем в правую панель редактора и введем в поле Name имя нашего класса — Author. Второму классу присвоим имя Book, а третьему — имя AuthorBook. После этого у нас должна получиться модель, представленная на рис. 5.

Теперь создадим атрибуты наших классов. Автор книги, как мы договорились раньше, описывается в нашей модели своим именем, а книга — названием. Следовательно, класс Author будет иметь один атрибут — назовем его aname, класс Book будет иметь также единственный атрибут, которому дадим название btitle. Класс AuthorBook пока трогать не будем. Для создания атрибутов выберем в левой панели редактора нужный класс, кликнем правой кнопкой мыши и из всплывающего меню выберем пункт New Attribute. Создадим по одному новому атрибуту для классов Author и Book, а затем раскроем дерево модели на левой панели редактора, как показано на рис. 6.

По умолчанию новые атрибуты получили имена (каждый в своем классе) — NewAttribute. Переименование атрибутов осуществляется так же, как и переименование классов (рис. 7).

Теперь вспомним о третьем классе, созданном нами, — AuthorBook. В принципе, как будет показано в дальнейшем, для такой простой модели, как наша, совсем необязательно создавать этот класс вручную — это можно сделать автоматически. Но на данном этапе этот класс будет полезен для иллюстрации возможностей описываемой технологии. Смысл создания этого класса — обеспечение связи между авторами и книгами, поэтому AuthorBook является не обычным классом, а носителем для ассоциации между классами Author и Book. Однако прежде чем определять этот класс в качестве носителя ассоциации, необходимо создать саму ассоциацию. Для этого поступаем так же, как и при создании новых классов: выбираем пункт LogicalView в дереве модели на левой панели редактора, после чего нажимаем правую кнопку мыши, но из всплывающего меню теперь выбираем пункт New Association, затем раскрываем дерево модели (рис. 8).

В правой панели редактора в окошке с именем класса мы видим, что имя класса — носителя для новой ассоциации (ей автоматически присвоено имя NewAssociation) отсутствует (<none>). Из выпадающего списка в этом окошке назначим для класса ассоциации имя ранее созданного нами класса — AuthorBook. Далее в дереве модели мы видим, что созданная ассоциация имеет два подпункта: AssociationEnd0 и AssociationEnd1, представляющие собой автоматически созданные названия для ролей нашей ассоциации. Определим эти роли: выделим роль ассоциации AssociationEnd0, в правой панели редактора введем в поле Name имя роли byAuthor, а в поле Class выберем из выпадающего списка класс Author; установим значение поля Multiplicity в «1..1» и снимем флажок Embed (рис. 9).

Затем выделим роль ассоциации AssociationEnd1, в правой панели редактора введем в поле Name имя роли writes, а в поле Class выберем из выпадающего списка класс Book. Далее установим значение поля Multiplicity в «1..*» и снимем флажок Embed (рис. 10).

Теперь немного порассуждаем, что именно мы только что сделали с ролями нашей ассоциации и почему. Как говорилось выше, в нашей модели принято упрощающее предположение о том, что книга может быть написана только одним автором. Именно по этой причине мы установили свойство Multiplicity у роли byAuthor в значение «1..1» (см. рис. 9), то есть один и только один (автор). Однако наша модель по умолчанию допускает, что автор может написать много книг, и поэтому на другом конце нашей ассоциации writes свойству Multiplicity назначено значение «1..*» (см. рис. 10), другими словами, одна, две.. много (книг). Теперь осталось только понять, почему «1..1» относится именно к автору, а «1..*» — к книгам. Но ведь эту привязку сделали мы сами, когда назначали классы для ролей!

В начало В начало

Создание графического интерфейса

Итак, к настоящему моменту мы создали основу бизнес-уровня, то есть модель приложения. Дошла очередь до графического интерфейса.

Сразу стоит напомнить об одном важном обстоятельстве, упомянутом в первой части статьи. При работе с Bold следует привыкнуть к наличию бизнес-уровня в вашем приложении, который существует не абстрактно, а заставляет нас использовать специальные компоненты для доступа к каким-либо структурам или данным. Эти компоненты не являются визуальными, а служат своеобразными трансляторами и реализаторами запросов, которые посылает графический уровень к бизнес-уровню для получения от последнего необходимой информации. Впоследствии мы убедимся, что наличие бизнес-уровня обеспечивает чрезвычайную гибкость и удобство, а сейчас используем один из таких невизуальных компонентов для поддержки нашего интерфейса. Перейдем на закладку BoldHandles и поместим на форму компонент BoldListHandle1. В инспекторе объектов установим значение свойства RootHandle равным BoldSystemHandle1 (его можно ввести вручную или выбрать из выпадающего списка).

Для свойства Expression введем выражение Author.allinstances (рис. 11). Кстати, это выражение представляет собой запрос к бизнес-уровню на языке OCL (Object Constraint Language), который в данном случае означает: «хочу получить все экземпляры класса Author». Подробнее об OCL мы поговорим далее.

Теперь создадим собственно графический интерфейс, для чего на закладке BoldControls имеется довольно много компонентов. Мы выберем два из них — BoldGrid и BoldNavigator, которые являются аналогами соответствующих компонентов доступа к данным со страницы Data Controls. Свойству BoldHandle обоих визуальных компонентов присвоим значение BoldListHandle1, после этого кликнем правой кнопкой мыши на компоненте BoldGrid1 и выберем пункт Create Default Columns (создать столбцы по умолчанию). В результате у компонента BoldGrid1 появится заголовок столбца aname (рис. 12).

Вот и все: мы создали наше первое — очень простое — приложение и можем его запустить на выполнение.

Можно также добавлять авторов (рис. 13), удалять или редактировать их. Но, как легко убедиться, после закрытия приложения и его повторного запуска все введенные данные исчезают. Это происходит потому, что наше приложение пока не содержит уровня данных (Persistence Layer).

В начало В начало

Создание уровня данных

Чтобы не отвлекаться сейчас на создание базы данных, на настройки псевдонимов и прочих вещей, для построения уровня данных используем очень удобное средство, встроенное в Bold, — хранение данных в XML-документе. Для этого с закладки BoldPersistence поместим на форму компонент BoldPersistenceHandleFileXML1 (рис. 14).

Для настройки компонента в инспекторе объектов просто установим значение его свойства BoldModel равным BoldModel1, а свойства FileName (имени файла) — например 1.xml (рис. 14). Кроме того, для компонента BoldSystemHandle1 установим в инспекторе объектов значение свойства PersistenceHandle равным имени компонента BoldPersistenceHandleFileXML1.

Чтобы наше приложение сохраняло свои данные, в процедуру обработки события OnClose нашей формы следует ввести одну строку кода:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
BoldSystemHandle1.UpdateDatabase;
end;

Теперь можно убедиться, что наше приложение приобрело способность сохранять данные. Пришло время подробнее изучить его возможности.

В начало В начало

Работа с приложением

Казалось бы, ничего особенного мы не получили. Создали, пусть и необычным способом, вполне обычную форму для ввода и редактирования данных по авторам. (Кстати, почему-то при этом мы не сделали форму ввода для названий книг, на что, видимо, уже обратил внимание проницательный читатель.) Но первое впечатление в данном случае обманчиво. Чтобы начать знакомство с «магией» Bold, добавим к нашему приложению один программный модуль: допишем в объявление Uses нашего модуля Unit1 модуль с названием BoldAFPDefault и запустим приложение на исполнение.

Введем в список авторов несколько значений (см. рис. 13). Теперь выберем автора Драйзер в таблице и кликнем дважды мышью по соответствующему значению, после чего откроется новое окно. Мы не создавали эту форму — за нас все сделал Bold. Форма имеет несколько закладок, одна из которых называется writes. Перейдя на эту закладку, мы обнаружим форму для ввода названий книг. Если, не закрывая новой формы, перейти на другого автора и опять кликнуть дважды на имени автора, то появится еще одна новая форма для ввода книг, написанных эти автором, а затем повторить все действия с третьим автором. Таким образом вы можете ввести названия книг, написанных всеми тремя авторами (рис. 15).

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

Проницательный читатель без труда обнаружит, что название writes закладки на автоформе есть не что иное, как название соответствующей роли ассоциации в нашей модели. А где же в таком случае название второй роли? Для того чтобы увидеть его, выберем какую-нибудь книгу на автоформе и дважды кликнем на ее названии (рис. 16). При этом появится новая форма, на которой мы увидим название книги, а под ней — серое поле с именем автора, слева от которого расположен заголовок byAuthor — это и есть вторая роль нашей ассоциации.

Учитывая, что мы практически не писали кода, не программировали события drag&drop мыши и не создавали формы для ввода названий книг, можно констатировать, что полученное приложение обладает очень неплохой функциональностью.

Однако будем двигаться дальше. Чтобы видеть более полную картинку происходящего, добавим на главную форму визуальные компоненты BoldGrid2 и BoldNavigator2 с закладки BoldControls для отображения списка книг и управления им. Для получения списка книг из бизнес-уровня нам понадобится также второй компонент BoldListHandle2 со страницы BoldHandles палитры компонентов. В инспекторе объектов установим значение свойства RootHandle этого компонента равным BoldSystemHandle1 (его можно ввести вручную или выбрать из выпадающего списка); значение свойства Expression установим равным OCL-выражению Book.allinstances. Свойству BoldHandle визуальных компонентов BoldGrid2 и BoldNavigator2 присвоим значение BoldListHandle2, после этого кликнем правой кнопкой мыши на компоненте BoldGrid2 и выберем пункт Create Default Columns, то есть создадим столбцы по умолчанию. В результате у компонента BoldGrid2 появится заголовок столбца btitle (рис. 17).

Конечно, вы уже поняли, что названия столбцов aname и btitle в таблицах BoldGrid1 и BoldGrid2 Bold автоматически выбирает из назначенных нами атрибутов в классах Author и Book, когда мы создаем столбцы по умолчанию. Но это, естественно, не означает, что мы не можем настроить таблицы BoldGrid по-другому (например, присвоить им русскоязычные названия) — просто сейчас мы выбираем наиболее простой и быстрый путь.

Запустим наше усовершенствованное приложение на выполнение. Добавим двух авторов — Ильф и Петров — с помощью навигатора. Добавим с помощью второго навигатора книгу «12 стульев». Кликнем дважды на названии этой книги (рис. 18). Перетащим с помощью мыши автора Ильф на автоформу на серое поле с именем автора. Мы увидим, что книге «12 стульев» был присвоен автор Ильф. Перетащим автора Петров на то же место и увидим, что автором книги стал Петров, а Ильф исчез. Мы с вами знаем, что данную книгу на самом деле написали оба автора, но при создании модели мы ввели бизнес-правило: «у каждой книги должен быть только один автор». Поэтому наше приложение, функционируя в рамках заданной модели, не позволяет добавить второго автора.

В начало В начало

Модификация модели приложения

Посмотрим, что произойдет, если мы изменим бизнес-правило, ограничивающее количество авторов у книги единственным автором, а вместо него сформулируем следующее бизнес-правило: «каждая книга может иметь несколько авторов». Для этого запустим редактор моделей, выберем роль byAuthor и установим для нее свойство Multiplicity равным «1..*» (рис. 19).

Далее удалим файл 1.xml из рабочей папки. Запустим приложение на выполнение. Опять добавим указанных авторов с помощью первого навигатора, а с помощью второго навигатора — книгу «12 стульев». Кликнем дважды на названии книги и убедимся, что автоформа изменилась (рис. 20).

Теперь вместо одного окошка для имени автора, как на рис. 18, мы обнаружим форму, позволяющую назначать данной книге произвольное число авторов. Перетащим последовательно обоих авторов на автоформу — и теперь у книги «12 стульев» имеются в наличии оба автора.

Только что мы с вами наблюдали на практике характерную и основную черту MDA-приложений, а именно: поведение MDA-приложения определяется не кодом приложения, а UML-моделью. Мы не исправили ни строчки кода (да и кода-то, строго говоря, нет, по крайней мере, написанного нами), но получили новую функциональность нашей программы. Почему? Потому что мы изменили модель приложения и этого оказалось вполне достаточно для изменения поведения приложения.

Продолжим изучение свойств созданного приложения. Добавим нового автора — Драйзер. Добавим во вторую таблицу книги — «Американская трагедия», «Гений», «Финансист». Кликнем дважды на имени автора Драйзер, откроем закладку writes на появившейся форме автора и перетащим с помощью мыши эти три книги из главной формы на форму автора (рис. 21).

Еще раз нужно напомнить, что при перетаскивании нужно помещать курсор не на название книги или автора, а на ячейку первого столбца, выделенную символами ромбика и стрелки, которые показывают текущее положение указателя.

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

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

Для реализации этого правила снова обратимся к нашей модели, выберем роль ассоциации writes и изменим значение параметра Delete Action с <Default> на Cascade (рис. 22).

Снова запустим наше приложение: добавим автора — Драйзер, которого мы удалили в прошлый раз, назначим ему уже известным способом три книги — «Американская трагедия», «Гений» и «Финансист». А теперь попытаемся снова удалить автора из главной формы и убедимся, что после его удаления из правого списка книг также исчезли и написанные им книги. Опять мы увидели, что изменение в модели приложения непосредственно сказывается на его поведении.

В начало В начало

Подведение итогов

Оценим, уже с новой позиции, функциональность созданного приложения. Мы построили с точки зрения прикладных возможностей классическое приложение для работы с локальной базой данных, которая содержит связи типа «многие-ко-многим». При этом:

  • не создавалась собственно база данных, а создавалась модель;
  • не создавались таблицы и поля, первичные и вторичные ключи и индексы, а создавались классы, содержащие атрибуты, и ассоциации, содержащие роли;
  • не создавались связи типа «главный—подчиненный» и «многие-ко-многим», а назначались размерности ролей;
  • не использовался язык SQL;
  • не программировались формы для ввода и редактирования данных, а были созданы автоматически;
  • не программировался интерфейс drag&drop.

Читатели, знакомые с разработкой приложений баз данных в Delphi, могут, наверное, реально оценить затраты времени на создание подобного приложения стандартными методами, а также объем работы при внесении изменений в структуру базы данных, что мы, по сути, и делали, когда изменяли размерности связей для авторов в нашей модели.

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

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

В начало В начало

Резюме

  1. На практике показано, что MDA-приложение организовано в виде «трехслойного пирога» и даже самое простейшее такое приложение содержит три уровня: уровень данных, бизнес-уровень и прикладной уровень (графический интерфейс).
  2. Продемонстрировано, что графический интерфейс обращается к данным через посредника — бизнес-уровень, для чего существуют специальные невизуальные компоненты.
  3. Показано, что, с одной стороны, функционирование MDA-приложений невозможно без создания модели, а с другой — что поведение приложения определяется этой моделью не абстрактно, а совершенно конкретно.

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

КомпьютерПресс 4'2003