Проектирование приложений с помощью Bold for Delphi и Model Maker

Автор: Михаил Голованов
Источник: RSDN Magazine #2-2003
Опубликовано: 19.07.2003
Версия текста: 1.0.1
Введение
Model Maker и Bold for Delphi. Общие сведения, назначение, области использования.
Model driven development с использованием Model Maker и Bold for Delphi
Этап 1. Выделение сущностей предметной области, построение UML-диаграммы классов
Этап 2. «Перевод» модели в объекты языка программирования Delphi.
Этап 3. Написание GUI.
Реализация отношения один-ко-многим
Реализация отношения многие ко многим
Резюме

Введение

Наиболее заметными нововведениями в Delphi 7 стало появление двух новых инструментов, Model Maker и Bold for Delphi. Данные инструменты позволяют с помощью Delphi осуществлять не только кодирование, но и, что очень важно, проектирование приложений.

Естественным желанием каждого программиста является исследование новых возможностей используемой им среды разработки. В данной статье я хочу поделиться результатами своих экспериментов с Model Maker и Bold. Как оказалось, эти инструменты позволяют вывести разработку приложений в Delphi на качественно новый уровень.

Model Maker и Bold for Delphi. Общие сведения, назначение, области использования.

Model Maker – это инструмент case-проектирования компании Model Maker tools BV. Данный продукт включен в состав Delphi 7, хотя может использоваться и отдельно. Основными возможностями Model Maker являются:

Использование Model Maker делает возможным создание приложения от этапа проектирования и до готового исходного кода без применения каких либо дополнительных case-инструментов.

Можно выделить две основных области применения продукта:

Bold for Delphi (существует также версия для C++ Builder), в свою очередь, – это технология быстрой разработки приложений на основе UML-моделей. Этот продукт создан компанией BoldSoft, недавно приобретенной Borland. Bold позволяет на основании UML-описания бизнес-процессов и бизнес-правил быстро и качественно спроектировать и с лёгкостью модифицировать информационную систему (ИС). Само UML-проектирование выполняется с помощью стороннего case-инструмента, а созданная UML-модель импортируется в Bold. На сегодняшний день Bold может импортировать модели из Rational Rose и Model Maker.

Каким же образом использование Model Maker и Bold может усовершенствовать процесс разработки ПО? Для ответа на этот вопрос рассмотрим сначала традиционный цикл создания программного продукта.

Традиционная модель разработки приложения баз данных включает в себя следующие этапы:

  1. Изучение предметной области. Выделение сущностей предметной области, их атрибутов и связей между ними.
  2. Проектирование базы данных. На данном этапе проектируется набор таблиц и реляционных связей для хранения каждой сущности.
  3. Создание графического интерфейса пользователя для управления сущностями.
  4. Реализация бизнес-правил в хранимых процедурах на сервере или в клиентском приложении.

Порядок следования этапов может быть несколько иным, но суть при этом не меняется.

Bold предлагает усовершенствованную модель, позволяющую программисту работать на уровне представления сущностей предметной области как классов, при этом необходимые структуры для хранения сущностей в БД создаются автоматически, без дополнительных усилий программиста. Кроме того, создаются и метаданные сущностей, позволяющие в дальнейшем быстро вносить изменения и дополнения в модель системы. Данный способ разработки приложения получил название «Model driven development», что можно перевести как «разработка на основе модели».

Модель приложения в Bold разделена на три слоя:

Попробуем рассмотреть на примере процесс разработки, основанной на модели.

Model driven development с использованием Model Maker и Bold for Delphi

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

Этап 1. Выделение сущностей предметной области, построение UML-диаграммы классов

Цель этапа : выделить сущности предметной области, их атрибуты и взаимосвязи.

Конечный результат: UML-диаграмма классов.

В результате беглого анализа задачи можно выделить сущность «Абонент» – лицо, информацию о телефонах которого требуется хранить. В нашем примере достаточно хранить ФИО абонента и номер его телефона.

После проведения анализа (или, точнее, первой его итерации) можно приступать к построению UML-диаграммы классов, представляющих сущности. Существует много инструментов, предназначенных для построения UML-диаграмм. Наиболее популярными из них являются Rational Rose, Power Designer, Model Maker. В данной статье я не буду обсуждать достоинства и недостатки каждого из этих продуктов. Свой выбор я остановил на Model Maker по нескольким причинам:

Для построения UML-диаграммы классов c помощью Model Maker следует запустить Model Maker :). Сделать это можно либо из IDE Delphi (ModelMaker/Run ModelMaker), либо через кнопку Пуск/Программы/… На экране появится главное окно программы (см. рисунок 1 ).


Рисунок 1. Главное окно Model Maker.

Окно содержит нескольких рабочих областей.

В левом верхнем углу расположена панель выбора режима работы. Она содержит следующие элементы:

Под панелью режимов работы расположено окно просмотра членов класса. Использование его вряд ли вызовет какие-либо трудности.

Справа вверху расположена основная панель инструментов, состоящая из набора закладок. Оставшаяся часть окна – это рабочая область, меняющая свой вид в зависимости от выбранной закладки основной панели инструментов.

Создадим новый проект. Проект – это набор UML-диаграмм, объединенных общей задачей. Различные UML-диаграммы позволяют спроектировать разные аспекты работы создаваемого приложения. Начальную часть проектирования мы выполнили «неформально», описав общие требования к приложению в текстовом виде, поэтому сразу переходим к созданию диаграммы классов. Для включения в проект диаграммы классов необходимо перейти на закладку Diagrams панели режимов работы и нажать на иконку Add class diagram. В основной панели инструментов нужно перейти на закладку Diagram Editor. Результат выполнения данных действий представлен на рисунке 1. Теперь можно начинать собственно проектирование класса абонента.

На закладке Diagrams нажмем кнопку Add Class to Model. В появившемся диалоге, приведенном на рисунке 2, введем имя класса TAbonent.


Рисунок 2.

От какого класса будет унаследован TAbonent, не играет роли, так как далее Bold все равно меняет родителя на другой базовый класс. После нажатия кнопки «OK» новый класс появится на диаграмме и в списке классов. Выбрав класс на диаграмме, добавим два свойства – AbonentName и AbonentPhone. Самым простой способ сделать это – использование кнопки добавления свойства класса (Add property) в окне просмотра членов класса. При нажатии на кнопку появляется диалог добавления свойства (рисунок 3).


Рисунок 3.

Оба свойства имеют тип AnsiString и прямой доступ на запись (в группе переключателей Write access надо выбрать переключатель Field). Все, проектирование нашего класса завершено.

Этап 2. «Перевод» модели в объекты языка программирования Delphi.

Цель этапа: Получить набор классов на используемом языке программирования (Delphi), соответствующий UML-диаграмме классов, полученной на этапе 1.

Конечный результат : набор классов, реализующий UML-диаграмму.

Для хранения и использования модели в Bold предназначен компонент TBoldModel, расположенный на закладке BoldHandelers IDE Delphi. Разместим данный компонент (впрочем, как и остальные) на главной форме нашего приложения. Для импорта диаграммы классов из Model Maker предназначен компонент TBoldUMLMMLink. Разместив этот компонент на форме, установим значение его свойства BoldModel равным BoldModel1 (имя компонента BoldModel), а свойства FileName – файлу проекта Model Maker, содержащего нашу диаграмму.

Для хранения модели нам потребуется реляционная БД и дополнительные компоненты, обеспечивающие запись/извлечение модели. В качестве сервера реляционной БД я использовал Interbase. По заверениям Borland, можно использовать и другой сервер БД. За сохранение и загрузку модели в базу отвечает компонент BoldPersistenceHandleDB. Разместим его на форме приложения. Установим необходимые свойства данного компонента.

Теперь можно импортировать диаграмму классов. Загрузим редактор моделей Bold. Для этого достаточно дважды щелкнуть мышью на компоненте TBoldModel. Внешний вид окна редактора приведен ниже.


Рисунок 4.

Для импорта модели необходимо воспользоваться кнопкой Import via Link (вторая слева на панели инструментов). После импорта в дереве просмотра модели появится узел с наименованием TAbonent, имеющий предком класс BusinessClassesRoot, а не TObject, как это было установлено при создании диаграммы классов в Model Maker. Связано это с тем, что Bold будет обрабатывать и хранить информацию как о самом классе, так и о созданных пользователем экземплярах класса. Стандартные классы VCL не рассчитаны на такое использование и поэтому не могут выступить непосредственными предками для классов модели.

Можно также описать бизнес-объекты, используя только редактор моделей Bold, но использование UML-диаграмм является, на мой взгляд, гораздо более удобным.

После импорта необходимо позаботиться о сохранении модели в базу данных. На главной форме приложения разместим следующие компоненты и установим их свойства:

Таким образом, цепочка компонентов для сохранения модели показана на рисунке 5.


Рисунок 5.

Такое разделение позволяет сделать процесс сохранение модели более гибким и не зависящим от БД (а в общем случае БД может быть заменена другим способом хранения информации).

После размещения и настройки компонентов, отвечающих за сохранение модели, вернемся в редактор модели и нажмем на его панели кнопку Generate database. При этом модель будет проверена на корректность и сохранена в БД. Кроме этого, нужно нажать кнопку Generate code для создания служебных модулей кода, создаваемых Bold. Эти модули автоматически включаются в проект и в большинстве случаев никак не проявляют себя.

Теперь можно переходить к созданию пользовательского интерфейса работы с сущностями БД.

Этап 3. Написание GUI.

Цель этапа: создание GUI, позволяющего работать с объектами предметной области в удобной и понятной форме.

Конечный результат: клиентская часть приложения.

Компоненты пользовательского интерфейса расположены на закладке Bold Controls. Большинство из них аналогично «обычным» data-aware компонентам.

Для работы со списком абонентов на главной форме приложения разместим компоненты BoldGrid (аналог DBGrid) и BoldNavigator (аналог DBNavigator). Все компоненты пользовательского интерфейса имеют свойство BoldHandle. Данное свойство ссылается на компонент-источник данных о сущностях модели.

Компоненты-источники данных модели используют язык описания объектов (Object Constraint Language - OCL). Этот язык предназначен для описания работы с данными UML модели Bold. Необходимость использования OCL обусловлена тем, что возможностей классических объектов для управления экземплярами сущностей и их связями на этапе run-time оказывается явно недостаточно. Кроме того, OCL позволяет нам мыслить на уровне атрибутов и связей объектов модели, а не классов, их реализующих, что скрывает особенности используемого языка программирования и позволяет полностью сосредоточиться на бизнес логике.

В качестве компонента – источника данных используем BoldListHandle, позволяющий работать со списком сущностей одного типа (в нашем случае абонентов). Разместим компонент BoldListHandle1 на главной форме приложения. Для работы OCL необходимо получить метаинформацию модели на этапе разработки. Данную информацию предоставляет компонент TBoldSystemHandle, который мы также положим на главную форму. Свойство RootHandle (источник метаинформации) компонента BoldListHandle1 установим равным BoldSystemHandle1. А свойство AutoActivate BoldSystemHandle1 в true. Теперь мы готовы описать на языке OCL, какую именно информацию мы хотим получить. Для этого двойным щелчком мыши на BoldListHandle1 раскроем OCL-редактор.


Рисунок 6.

Окно редактора разделено на три основные части:

В списке объектов дважды щелкнем на классе TAbonent, сущности которого нам необходимо отображать пользователю. При этом будет выведен список OCL-операторов для работы с данным классом. Двойным щелчком на элементе .allInstances укажем, что мы хотим получить все экземпляры данной сущности. При этом в поле ввода появится выражение OCL TAbonent.allInstances. Конечно же, его можно было ввести руками, но описанный выше способ удобнее и быстрее. Теперь можно закрыть редактор, нажав кнопку OK.

Установим свойство BoldHandle компонентов BoldGrid1 и BoldNavigator1 равным BoldListHandle1, чтобы они работали со списком абонентов. В контекстном меню компонента BoldGrid1 выберем пункт «Create default columns», при этом будет сгенерирован список колонок, соответствующих полям сущности абонента. Двойным щелчком мыши на BoldGrid1 вызовем редактор колонок сетки и установим русифицированные заголовки столбцов AbonentName и AbonentPhone. Наше приложение готово к перовому запуску.

Запустим приложение и введем первого абонента. Теперь попробуем закрыть приложение. Вот тут нас подстерегает маленькая неприятность в виде сообщения "Destroying system with dirty objects" (это текст сообщения по умолчанию, его можно, и даже нужно поменять на более осмысленное). Данное сообщение говорит о том, что созданные нами новые экземпляры сущностей не сохранены в базе. То есть Bold после загрузки сущностей из БД не обращается каждый раз к базе при создании нового экземпляра сущности или модификации существующего экземпляра, и при попытке закрыть приложение честно предупреждает, что изменения не сохранены. Более того, если мы повторно запустим приложение, то не увидим введенных нами данных. Для сохранения изменений необходимо вызывать BoldSystemHandle1.System.UpdateDatabase. Данный вызов удобнее всего поместить в обработчик OnClose главной формы. Ну вот, первое Bold-приложение готово.

Реализация отношения один-ко-многим

Еще в самом начале рассмотрения примера прозорливый читатель наверняка воскликнул: «Что за ерунда? Каждый абонент может иметь несколько телефонных номеров!» Но не спешите кидать в меня помидорами :). Если добавить в модель отдельную сущность «Телефон», то проблема будет решена. При этом факт обладания одного абонента несколькими телефонными номерами означает наличие связи один ко многим между сущностями «Абонент» и «Телефон». Еще более прозорливый читатель снова потянется за упомянутым овощем, так как в реальной жизни и один телефон может принадлежать нескольким абонентам (офисный телефон). Но не спешите, доберемся и до этого случая. А пока будем считать, что абонент имеет один и более телефонов, но телефон всегда принадлежит одному абоненту.

Внесем соответствующие изменения в диаграмму классов приложения. В классе TAbonent добавим свойство-ссылку на класс TPhone. Имя данного свойства – Phone. Добавим свойство с помощью кнопки Add Property to model. На закладке Vizualization установим стили отображения обоих концов связи в Undefined, чтобы избежать отображения стрелок. Source role – owned, Source Multiplicity – 1, Target role – have phone, Target multiplicity – 1..*. Диаграмма классов при этом будет выглядеть так, как показано на рисунке 7


Рисунок 7.

При добавлении свойства OwnerAbonent линию, соединяющую классы на диаграмме, следует начинать с класса TPhone и завершать на классе TAbonent. Установленная связь означает, что класс TAbonent имеет один или несколько экземпляров TPhone, а TPhone всегда принадлежит лишь одному TAbonent.

Сохраним данную модель и импортируем ее в редактор модели Bold. На рисунке 8 приведен фрагмент измененной модели в окне редактора.


Рисунок 8.

Что же изменилось в модели? Как видим, появился класс TPhone с заданными нами атрибутами. А также появился новый вид объектов модели Associations. В нем описаны взаимосвязи классов. Существуют две позиции ассоциации Phone, описывающие связь сущностей «Абонент» и «Телефон». Каждая позиция соответствует одному концу связи. Не забудьте сгенерировать исходный код и базу данных заново, так как модель изменилась.

Теперь осталось лишь позаботиться о графическом интерфейсе пользователя. Сначала приведем в порядок Grid для отображения сущности «Абонент», а именно – удалим оттуда столбец, соответствующий номеру телефона, так как номер телефона теперь вынесен в отдельную сущность. Затем на форму положим еще один BoldGrid и BoldNavigator для работы с сущностью «Телефон», и разместим на форме еще один компонент TBoldListHandle (BoldListHandle2) для работы из OCL с данной сущностью.

Свойство RootHandle для BoldListHandle2 установим равным BoldListHandle1. Именно это определяет, что второй список будет отображать телефоны выбранного абонента. В OCL-редакторе зададим выражение have_phone, означающее, что нам нужно отображать элементы ассоциации, указывающие на телефоны абонента. Для BoldGrid2 и BoldNavigator2 (отображающие телефоны) свойство BoldHandle установим равным BoldListHandle2. В BoldGrid2 сгенерируем колонки по умолчанию и зададим им русские заголовки. Ну вот и все, можно запускать приложение.

Реализация отношения многие ко многим

Приведем наш проект к еще более реалистичному виду. Ранее мы считали, что один телефон может принадлежать только одному абоненту. На самом деле это не совсем так. Например, по одному офисному телефону могут располагаться несколько абонентов. То есть абонент и телефон связаны отношением многие ко многим. Нет ничего проще, чем реализовать данную модель в Bold.

Сначала внесем коррективы в модель классов. На закладке Vizualiztion зададим для связи отношение многие ко многим и имена ролей have phones и have abonents соответственно для классов TAbonent и TPhone. Имя свойства класса TAbonent изменим на OwnedPhones, чтобы оно более точно отражало изменившееся назначение. Исправленная диаграмма будет иметь вид, показанный на рисунке 9.


Рисунок 9

Импортируем модель в Bold. В редакторе модели Bold она будет выглядеть так, как показано на рисунке 10.


Рисунок 10.

Обратите внимание на то, как была сгенерирована ассоциация. Bold представил отношение "многие ко многим" через отдельный класс-посредник OwnedPhones. Если выбрать свойства ассоциации, можно увидеть, что ассоциация является экземпляром класса OwnedPhones.

Нам остается только добавить пользовательский интерфейс для работы с изменившейся моделью. В качестве примера я сконструировал форму, изображенную на рисунке 11.


Рисунок 11

Однако для ввода она не очень удобна, так как при вводе телефонов абонента происходит создание новых объектов сущностей "телефон" и, наоборот, при вводе абонентов для телефонов создаются новые абоненты. Таким образом, мы не можем присвоить один телефон многим абонентам или одного абонента нескольким телефонам.

Для решения данной проблемы мы расположим на форме дополнительный компонент TBoldPlaceableAFP с закладки Bold Misc. Данный компонент позволяет на этапе выполнения автоматически конструировать формы, работающие с элементами сущностей. Для BoldGrid вызов автоформы осуществляется по двойному щелчку мышью. На рисунке 12 приведен вид автоформы для работы с абонентом.


Рисунок 12.

Обратите внимание на стрелку в правом нижнем углу. Перетягивание данной стрелки на Grid с абонентами телефонного номера добавляет данного абонента во владельцы телефона. Аналогично действует и стрелка на автоформе телефонов.

Резюме

Итак, не написав ни одной строчки кода, мы создали достаточно функциональный телефонный справочник. Какие выводы мы можем сделать?

  1. Программирование с помощью Bold требует несколько большей фундаментальности в подготовке программиста. Он должен начать думать сущностями предметной области и овладеть базовыми знаниями архитектуры Bold.
  2. Связка Model Maker и Bold позволяет осуществлять сквозное проектирование приложения в Delphi, начиная от этапа разработки концептуальной диаграммы сущностей и заканчивая кодированием приложения.
  3. Применение Bold в России может сдерживаться необходимостью локализации приложения. Вопросы локализации требуют отдельного исследования за рамками данной статьи.

Данная статья является лишь введением в использование Model Maker и Bold. Ограничиться рассмотрением случая программирования мышкой означало бы лишь поверхностно осветить вопросы, связанные с использованием данных продуктов. В следующих статьях мы коснемся более глубоких аспектов работы с ними.


Эта статья опубликована в журнале RSDN Magazine #2-2003. Информацию о журнале можно найти здесь