BOLD инструмент реализации MDA в Delphi
Часть 7. Объектное пространство и OCL. Графический интерфейс
Пример приложения с исходными текстами
Borland MDA и Microsoft .NET
конце сентября текущего года вышла новая версия инструментальной среды разработки Borland для платформы Microsoft .NET Borland C# Builder Architect. Наш журнал уже писал о появлении продукта Borland C# Builder1, однако, с точки зрения предмета данного цикла статей, целесообразно сказать несколько слов именно об этой, последней версии нового продукта разработки компании Borland.
Принципиальным отличием версии Architect от ранее вышедших версий продукта Borland C# Builder является присутствие в ней средств разработки MDA-приложений. Из их состава важнейшим элементом является интегрированная в Borland C# Builder Architect технология ECO — Enterprise Core Objects. Читатели, ознакомившиеся с технологией Bold for Delphi, обнаружат в ECO очень много общего с Bold. И это не случайно, поскольку ECO базируется на технологии Bold.
С целью полной интеграции MDA-инструментов в среду разработки компания Borland сделала еще один весьма логичный шаг: в состав Borland C# Builder Architect теперь включен полнофункциональный редактор UML-моделей, созданный на базе продуктов TogetherSoft2. Благодаря этому Borland C# Builder Architect стал первым продуктом Borland, обеспечивающим полный жизненный цикл разработки приложений — от создания модели до генерации кода.
Доработка приложения
озвращаясь к нашему приложению3, модель которого представлена на рис. 1, продемонстрируем возможности, предоставляемые поддержкой в Borland MDA языка объектных ограничений OCL, а также рассмотрим некоторые визуальные компоненты Borland MDA.
Для начала, по аналогии со списками авторов и книг, подключим визуальные компоненты BoldGrid5, BoldGrid6 и BoldGrid7 к описателям списков ListAllCountries, ListAllPublishers, ListAllThematics соответственно, то есть будем отображать в этих компонентах списки стран, издательств и тематических направлений книг (рис. 2), для начала создав в них столбцы по умолчанию (то есть столбец «Название»). Для сохранения данных запишем в обработчик события OnClose формы следующий оператор: DataModule1.BoldSystemHandle1.UpdateDatabase;
Запустим наше приложение, заполним таблицы со списком авторов, книг, стран, издательств и тематики данными4 и убедимся, что они сохраняются при выходе из приложения. Теперь можно более подробно познакомиться с организацией взаимодействия бизнес-уровня и графического интерфейса.
OCL и графический интерфейс
оставим следующую задачу: отображать в метке BoldLabel1 название страны, где проживает текущий автор, выбранный в списке авторов BoldGrid1 (рис. 2).
Обратите внимание, что метка BoldLabel1, как и любой другой визуальный компонент Borland MDA, имеет свойство BoldHandle. Из предыдущей статьи данного цикла нам известно, что в качестве источника данных для этого описателя целесообразно выбрать ListAllAvtors, что мы и сделаем. А в качестве OCL-выражения напишем вручную или введем во встроенном OCL-редакторе (напомним, что OCL-редактор вызывается при двойном щелчке по свойству Expression компонента ListAllAvtors) следующее выражение: «’Страна ‘+strana.nazvanie», где ‘Страна ’ — это текстовая константа, а «strana.nazvanie» — OCL-запрос для выбора страны для текущего автора и выбора атрибута «название» класса «’Страна’ — nazvanie» для отображения его на нашей форме. Как видим, это делается весьма просто. Встроенный в Borland MDA механизм обеспечит при этом автоматическое изменение текста метки при изменении текущего автора в компоненте BoldGrid1. На этом моменте стоит остановиться подробнее — как уже упоминалось ранее, одним из важных механизмов, встроенных в Borland MDA, является механизм так называемой подписки на события (subscribing). Рассмотрим работу данного механизма.
В нашем случае, связав свойство BoldHandle метки с описателем списков авторов ListAllAvtors, мы «сообщили» среде Borland MDA, что необходимо «подписать» нашу метку на события, возникающие при любых изменениях списка авторов, в том числе и на события, возникающие при переходах от одного объекта к другому при перемещении по списку авторов. Кроме того, мы сформировали OCL-запрос, который должен быть выполнен при наступлении такого события, с указанием конкретной необходимой нам информации (название страны, где проживает автор). Остальное среда Borland MDA сделает самостоятельно, то есть по наступлению события, связанного с изменениями в списке авторов, проверит, есть ли элементы, подписавшиеся на изменение этого списка, и, если таковые имеются, выполнит соответствующий OCL-запрос, а также вернет полученные данные подписанному элементу для дальнейшего использования (в данном случае — для отображения на форме). Отметим, что в данном случае «подписку» незаметно для нас «оформила» сама среда, но это совсем не обязательно. Разработчик может и самостоятельно «подписать» любой Bold-элемент на необходимое событие, воспользовавшись специальными методами класса TboldElement.
Читатель вправе спросить, что же здесь нового. Мы знаем, что при традиционной разработке приложений с базами данных можно использовать визуальный компонент TDBLabel — метку, которая автоматически отслеживает и отображает на форме содержимое указанного поля таблицы БД при перемещении по сетке. Однако в нашем классе «Автор» отсутствует атрибут «Страна» и для решения этой задачи традиционными методами нужно было бы сформировать в общем случае SQL-запрос, который бы выбирал страну из другой таблицы для конкретного автора и связать метку с этим запросом. Кроме того, необходимо было бы специально «подключать» этот запрос к сетке либо к набору данных, чтобы он выполнялся при переходах между авторами. Мы же обошлись без подобных операций.
Аналогично проделаем операции по подключению Bold-меток BoldLabel2 (для отображения названия издательства книги) и BoldLabel3 (для отображения тематики книги). В качестве источника информации для этих меток выступает описатель списка книг ListAllBooks. После запуска приложения убеждаемся, что тексты меток отслеживают перемещение по списку книг, отображаемых в компоненте BoldGrid3.
OCL и вычисляемые данные
спользование OCL в Borland MDA обеспечивает чрезвычайно гибкие механизмы получения разнообразных данных. На примере нашего приложения рассмотрим некоторые из них. Обратимся для этого к компоненту BoldGrid7, отображающему тематику книг. До этого момента в данном компоненте присутствовал всего один пользовательский столбец, отображающий название тематики. Сейчас мы поставим дополнительную задачу: показывать в этом же компоненте суммарное количество книг по данной тематике, для этого нужно добавить еще один столбец, кликнем дважды по соответствующему компоненту — в результате отобразится редактор столбцов (рис. 3, справа вверху). Добавление столбца осуществляется аналогично тому, как это делается в стандартном компоненте Grid. Присвоим новому столбцу название «Книг» (оно будет отображаться в заголовке столбца). Однако на этом аналогия с традиционным компонентом заканчивается — как мы видим (Рис.3, слева) , в инспекторе объектов снова присутствует уже знакомое нам свойство «Expression». Введем в него вручную или с помощью OCL-редактора выражение «knigi ->size.asString». В данном случае оно означает, что необходимо взять значение роли ассоциации класса «Тематика» с названием «книги» (см. модель на рис.1), затем получить количество элементов этой роли — оператор «->size » и, наконец, преобразовать полученное выражение в строку «.asString». Тем самым мы решили поставленную задачу.
Аналогично, в компоненте BoldGrid6 добавим столбец для отображения количества книг, изданных конкретным издательством. В этом случае OCL-выражение, как легко убедиться, будет тем же самым, поскольку название роли такое же, что и в предыдущем случае.
И наконец, обратимся к компоненту BoldGrid5, отображающему названия стран. До этого момента в нем отображался всего один столбец, созданный по умолчанию и содержащий название страны. Предположим, что мы хотим получить дополнительную статистическую информацию по каждой стране, а именно — общее количество авторов, проживающих в этой стране, общее количество издательств, а также общее количество всех изданных в данной стране книг. Для этого добавим к сетке BoldGrid5 три новых столбца — с названиями «Авт», «Изд», «Книг». Для столбца «Авт» выражение OCL примет следующий вид: «avtory->size.asString», для столбца «Изд»: «izdatel_stva ->size.asString». Однако для последнего столбца подобное простое выражение не будет являться решением, поскольку алгоритм расчета суммарного количества книг оказывается более сложным. В самом деле, в нашей модели отсутствует ассоциация, непосредственно связывающая оба класса — «Страна» и «Книга», и это вовсе не считается недостатком модели, поскольку вся необходимая информация для решения поставленной задачи у нас есть.
Алгоритм решения на естественном языке можно сформулировать для данного случая примерно так: для каждой страны необходимо выбрать все ее издательства, получить количество книг, изданных каждым издательством, и просуммировать все полученные величины. На языке OCL данный алгоритм может быть реализован посредством следующего выражения:
«izdatel_stva->collect(knigi->size)->sum».
Здесь мы впервые сталкиваемся с операторами взятия коллекции «->collect» и оператором суммирования «->sum». Смысл их вполне ясен из рассмотренного примера.
Можно сказать, что во многом оператор коллекции схож с известным SQL-оператором группировки «group by». Стоит отметить, что оператор получения коллекции применяется в OCL-выражениях довольно часто. После запуска приложения можно убедиться, что оно приобрело новые, необходимые нам качества (рис. 4).
На этом мы завершаем описание основных возможностей OCL. На примере созданного приложения были продемонстрированы основные подходы к реализации взаимодействия бизнес-уровня и графического интерфейса пользователя. Мы убедились на практике, что при использовании Borland MDA эта среда обеспечивает принципиально новые возможности по формированию такого взаимодействия благодаря встроенной поддержке языка OCL. Так, любой визуальный элемент приобретает способность отображать практически любые данные, содержащиеся в объектах объектного пространства. В рассмотренном примере мы «заставили» метки и сетки отображать информацию из объектов, принадлежащих разным классам нашей модели, и даже получать новую информацию, которая непосредственно в модели не содержится (статистические данные по странам, издательствам и т.д.). Необходимо отметить, что формирование такого рода взаимодействий не ограничивается этапом разработки приложения. Любое OCL-выражение можно формировать и присваивать и во время выполнения программы, при этом OCL-запрос будет исполнен средой Borland MDA, поскольку OCL-интерпретатор включается в состав исполняемого exe-файла приложения, так же как и вся информация о модели.
Нельзя еще раз не отметить, что при создании приложения мы не писали код на языке Object Pascal, и не использовали язык SQL, но, тем не менее, смогли «завязать» все элементы нашей модели в одно целое. Использование OCL позволяет сделать приложение более платформенно-независимым, так как язык OCL сам является платформенно-независимым языком. На практике это означает, что бизнес-логика приложения, будучи один раз создана на языке OCL без кодирования на языках программирования, при переносе разработки на другую платформу полностью сохранится и может быть повторно использована. И это является еще одним преимуществом технологии Borland MDA.
OCL и вычисляемые атрибуты
ще одним применением языка OCL в Borland MDA является использование OCL-выражений для определения вычисляемых (derived) атрибутов. Вычисляемые атрибуты, по аналогии с вычисляемыми полями традиционных компонентов для работы с базами данных, не сохраняются в базе данных, а их значения рассчитываются во время работы приложения в Borland MDA в момент первого обращения к значению такого атрибута. Формирование вычисляемых атрибутов происходит на этапе создания модели приложения, при этом разработчик в редакторе моделей (встроенном или в Rational Rose) помечает атрибут флажком «derived» и вводит OCL-выражение для его вычисления. Эта операция достаточно тривиальна. Для иллюстрации использования таких атрибутов достаточно отметить, что на этапе разработки модели нашего приложения мы могли ввести в состав классов модели вычисляемые атрибуты, отображающие статистические данные (количество авторов по стране, изданных книг и т.д), с использованием тех же самых OCL-выражений, которые мы формировали для дополнительных столбцов в нашем примере. В этом случае, имея такие атрибуты в составе классов, мы бы автоматически получили нужные столбцы в компонентах, отображающих эти статистические данные, без необходимости формирования дополнительных столбцов.