BOLD инструмент реализации MDA в Delphi
Часть 6. Объектное пространство и OCL
Формирование OCL-запросов к Object Space
Использование цепочек описателей
предыдущей части статьи мы остановились на иерархии внешних классов объектного пространства Borland MDA, а именно на описателях (handles), при практическом использовании которых активно задействуется язык объектных ограничений Object Constraint Language (OCL).
Язык OCL был разработан как средство описания дополнительных условий и ограничений, налагаемых на элементы диаграммы классов UML, и в этом плане является частью UML. OCL — продукт корпорации IBM, а в 1997 году вышла спецификация языка версии 1.1, в разработке и согласовании которой приняли участие такие компании, как Rational, Microsoft, Oracle, Hewlett-Packard и ряд других (полный текст спецификации на английском языке содержится на прилагаемом к журналу CD-ROM). Язык OCL представляет собой формальный язык, основанный на выражениях. Любое выражение OCL возвращает некоторое значение, при этом средствами OCL невозможно изменять ни диаграммы классов UML, ни значения атрибутов классов. OCL не является языком программирования в обычном смысле и не предназначен для управления логикой функционирования модели.
В Borland MDA язык OCL играет чрезвычайно важную роль, выполняя следующие основные функции:
• навигация по элементам модели (классам, атрибутам, ассоциациям);
• задание условий и ограничений на элементы модели.
Навигация по модели, обеспечиваемая в Borland MDA посредством OCL, позволяет использовать гибкий и мощный механизм запросов к объектному пространству приложения. Такие OCL-запросы, как мы увидим в этой и последующих частях статьи, в принципе, способны полностью заменить привычный разработчикам приложений баз данных язык SQL, обладая при этом несопоставимой с последним наглядностью, лаконичностью и мощностью. Кроме того, с учетом платформенной независимости OCL, эти запросы являются универсальными и не привязаны ни к какой конкретной СУБД, используемой в приложении.
Развитие модели
ля иллюстрации использования OCL при работе с описателями объектного пространства усовершенствуем нашу модель приложения1, добавив в нее дополнительные классы и ассоциации (рис. 1). Напомним, что наше приложение предназначено для работы с библиотечным каталогом, а в новую модель включены следующие классы: Страна, Издательство и Тематика.
Сформулируем основные бизнес-правила, определяемые новой моделью:
• библиотечный каталог содержит информацию об авторах, книгах, издательствах, странах и тематике книг;
• автор описывается единственным текстовым атрибутом — ФИО;
• элементы, то есть классы (Страна, Книга, Издательство, Тематика), описываются единственным текстовым атрибутом — Название;
• каждый автор может написать одну или несколько книг;
• каждая книга может быть написана одним или несколькими авторами;
• каждый автор является гражданином одной страны;
• в каждой стране может проживать несколько авторов или ни одного;
• в каждой стране может существовать несколько издательств или ни одного;
• каждое издательство принадлежит только одной стране;
• каждое издательство может издать одну или несколько книг;
• каждая книга может быть издана только одним издательством;
• каждая книга может относиться только к одной тематике;
• может существовать несколько книг по одной тематике или не существовать ни одной книги по данной тематике.
Создадим модель в редакторе Rational Rose и сохраним ее в какой-нибудь папке на диске, присвоив название lib.mdl и предварительно обработав с целью преобразования русскоязычных названий классов и атрибутов в англоязычные2. Можно также воспользоваться готовой моделью3.
Создание приложения
оздадим новый проект в Delphi, состоящий из одной формы и модуля данных. С палитры компонентов поместим на модуль данных компоненты и настроим их свойства в соответствии с приведенной на рис. 2 диаграммой.
Теперь приступим к созданию графического интерфейса формы (рис. 3). Поместим на форму 7 визуальные компоненты BoldGrid1, BoldGrid2…BoldGrid7 (на рисунке их номера представлены красными цифрами), далее над каждым из них расставим по одной обычной метке (Label) для удобства привязки, присвоив меткам названия: Все авторы, Все книги и т.д. Под компонентами BoldGrid 1, 3, 5, 6, 7 поставим по одному компоненту BoldNavigator. А затем поместим три компонента BoldLabel (на рисунке они обведены красным), пока не настраивая их свойства (эти компоненты показаны в настроенном виде). Мы создали графический интерфейс, однако он еще не привязан к объектному пространству. Для осуществления такой привязки используем невизуальные компоненты — описатели списков BoldListHandles с палитры компонентов BoldHandles, и покажем на нашем примере, как используется язык OCL для взаимодействия графического интерфейса (уровня представления) с объектным пространством (бизнес-уровнем).
Формирование OCL-запросов к Object Space
оместим компонент-описатель списка BoldListHandle1 на форму и присвоим ему название ListAllAvtors. Задачи данного описателя — получение из объектного пространства списка всех имеющихся авторов и передача этого списка визуальному компоненту BoldGrid1 для отображения. Описатель списка относится к производным описателям (см. предыдущую часть статьи), то есть обладает свойством <RootHandle> (корневой описатель), указывающим на источник информации. В данном случае таким источником является компонент-описатель всего объектного пространства BoldSystemHandle1. Поэтому в инспекторе объектов назначим свойству RootHandle компонента ListAllAvtors значение DataModule1.BoldSystemHandle1. Теперь сформулируем OCL-запрос, который обеспечит получение нужной нам информации об авторах. Обратимся к свойству <Expression> нашего описателя списка, описывающему выражение на языке OCL, посредством которого реализуется выбор необходимой информации. Это выражение можно ввести вручную, как мы делали раньше, рассматривая пример простого приложения4 , но удобнее воспользоваться OCL-редактором, встроенным в Borland MDA. Для его активации кликнем дважды в инспекторе объектов на свойстве <Expression>, при этом откроется окно редактора (рис. 4).
OCL-редактор устроен довольно просто: в верхней части имеется окно для ввода выражений на языке OCL, внизу под ним располагается окошко для отображения информации о корректности выражения и типе возвращаемого результата, а справа находится многофункциональное навигационное окно. До тех пор, пока мы не сформулировали OCL-выражение, навигационное окно отображает доступные элементы нашей модели (значки с красной полоской).
Поскольку нас сейчас интересуют авторы, кликнем дважды в навигационном окне по элементу Avtor — окно редактора изменится (рис. 5): в верхнем окне появилось выражение «Avtor»; нижнее окошко сообщает нам, что синтаксис OCL-выражения корректен, а тип возвращаемого результата — метатип (то есть класс модели); наконец, радикально изменилось содержимое навигационного окна, теперь в нем отображается список возможных OCL-операторов, применимых к нашему выражению (значки с желтой полоской). В самом верху этого списка находится нужный нам оператор <.allInstances> (Все сущности) — в данном случае все объекты типа <Автор>, поскольку мы уже частично задали наше OCL-выражение.
Кликнув дважды по этому элементу, мы увидим картину, представленную на рис. 6. Возвращаемый теперь тип результата — нужная нам коллекция объектов типа <Автор>.
Если обратить внимание на навигационное окно, то можно увидеть характерное разнообразие отображаемых в нем элементов. Здесь присутствуют ассоциации и их роли (значки с зеленой полоской), но не все, а только связанные с классом <Автор>. Также имеются атрибуты класса (значки с синей полоской) — в данном случае единственный атрибут «ФИО» класса <Автор>. И, конечно, по-прежнему присутствуют возможные OCL-операторы, с помощью которых можно «детализировать» наше выражение. Позже мы расскажем, как использовать эти богатые возможности, а сейчас отметим некоторые принципиальные моменты. Во-первых, несмотря на кажущуюся простоту, OCL-редактор является исключительно мощным средством формирования OCL-запросов. Обладая интеллектом и знаниями о модели, он динамически формирует возможные варианты последовательной детализации OCL-выражения и отображает их в навигационном окне. Во-вторых, как мы уже убедились, синтаксис OCL-выражений использует dot-нотацию, то есть его отдельные элементы отделяются точкой.
Выйдем из OCL-редактора и присвоим свойству BoldHandle компонентов BoldGrid1 и BoldNavigator1 значение ListAllAvtors. Далее правой кнопкой мыши на компоненте BoldGrid1 из всплывающего меню выберем пункт Create Default Columns и убедимся, что появился заголовок столбца «ФИО». Таким образом мы подключили визуальный компонент BoldGrid1 к объектному пространству посредством описателя списка ListAllAvtors.
Продолжим создание нашего приложения. По аналогии с настройкой списка всех авторов создадим описатель списка ListAllBook для получения списка всех книг. Это легко можно сделать самостоятельно, единственное отличие будет заключаться только в OCL-выражении, которое в данном случае будет выглядеть как «Kniga.allInstances». Список книг мы будем отображать в BoldGrid3, для чего свяжем уже известным нам способом компоненты BoldGrid3 и BoldNavigator2 c описателем списка ListAllBook.
Использование цепочек описателей
о сего момента мы, по сути дела, не сделали ничего принципиально нового по сравнению с рассмотренным в предыдущих частях примером простого приложения, хотя и начали применять возможности OCL-редактора. В этом разделе мы ознакомимся с технологией использования цепочек описателей списков. Поставим перед собой следующую задачу — отобразить в BoldGrid2 только книги, написанные конкретным автором, который выбран в BoldGrid1. Для этого поместим новый описатель списка и назовем его ListAvtorBooks. Принципиальным моментом в данном случае является выбор корневого описателя, в качестве которого логично взять не описатель всего объектного пространства BoldSystemHandle1, а созданный нами ранее описатель списка авторов ListAllAvtors. Тем самым мы формируем цепочку описателей (рис. 7), где каждый последующий элемент ссылается на предыдущий через свойство <Root Handle>.
Присвоим в инспекторе объектов свойству <RootHandle> описателя ListAvtorBooks значение ListAllAvtors и запустим OCL-редактор (рис. 8). Хотя мы еще не ввели никакого OCL-выражения, но в навигационном окне отображаются теперь не все элементы нашей модели, а лишь те, которые относятся к классу <Автор>.
Это и понятно, ведь в качестве корневого описателя, то есть поставщика информации, мы выбрали не все объектное пространство, а лишь один его класс.
И теперь нам осталось дважды кликнуть по названию роли «napisal» и убедиться, что тип возвращаемого результата — это коллекция объектов типа <Книга>. После подключения BoldGrid2 к описателю ListAvtorBooks можно считать, что поставленная задача решена.
Даже на таком простом примере в полной мере проявляется гибкость, предоставляемая средой Borland MDA. В следующей части статьи мы продолжим разработку нашего приложения и более детально ознакомимся с возможностями OCL.