В своих предыдущих
статьях я несколько раз упоминал о технологии
MDA. В этой статье я хочу рассказать, что же
такое MDA в понимании Borland, и какие
возможности открывает эта технология.
Итак,
представьте себе, что вы студент, и как всякий
обычный студент в течение семестра вы
занимаетесь массой нужных дел и, в общем, с
пользой проводите время. Но увы, ближе к концу
семестра приходит понимание того, что все эти
дела никак не были связанны с процессом вашего
обучения. И все бы было ничего, да только
курсовой по программированию грозит обернуться
для вас серьезной проблемой, поскольку сделать
его вы просто не успеваете. Что же делать? Тут
есть несколько вариантов. Вариант первый: найти
похожий курсовой в инете, слегка переделать его
и попробовать сдать. Но «злобный преподаватель»
тоже наслышан о таком явлении как Интернет и
тоже знает где лежат курсовые. Вариант второй:
заказать курсовик и заплатить за него
определенную сумму. Недостаток этого варианта
очевиден. Деньгам можно найти и более разумное
применение. О третьем варианте я даже не хочу
упоминать. Что же остается? Остается последний,
и как по мне, самый правильный вариант. Успеть
написать курсовик самостоятельно. Вот здесь нам
и поможет технология MDA.
В чем же ее суть? MDA (Мodel Driven
Architecture) дословно переводится как
«архитектура, управляемая моделью». Концепция
MDA разрабатывается консорциумом OMG (Object
Management Group), в который сегодня входит
более 800 компаний — производителей программного
и аппаратного обеспечения. Согласно концепции
MDA мы начинаем разработку приложения с создания
модели приложения, определяя его состав,
структуру и поведение.
Модель мы создаем не на языке
программирования, а посредством языка
унифицированного моделирования (UML) и полностью
абстрагируемся от особенностей конкретных
программных и аппаратных средств реализации
приложения. Такая модель называется
платформенно-независимой (Platform Independent
Model, PIM).
На втором этапе, после создания PIM, мы
создаем платформенно-зависимую модель PSM
(Platform Specific Model), которая является
своеобразным адаптером, обеспечивающими
интеграцию PIM с одной или несколькими
технологиями разработки программных продуктов.
Наконец, на заключительном этапе, на
основании PIM и PSM генерируется код приложения
и, при необходимости, база данных. При этом
генерация кода и баз данных осуществляется
автоматически, посредством специальных
инструментальных программных средств.
Таким образом, в соответствии с концепцией
MDA, главный акцент при разработке приложений
переносится с, собственно, этапа
программирования на этап создания модели. Что
это нам дает на практике? Я не буду углубляться
в теоретические аспекты, а выделю два основных
преимущества такого подхода. Во-первых, MDA
приложение полностью реализует бизнес–логику
ввиду того, что приложение строго соответствует
модели. Во-вторых, существенно ускоряется
процесс создания приложения, за счет
автоматической генерации кода приложения и
структур данных. И это «во-вторых» особенно
важно в нашей ситуации. Однако здесь следует
остановиться и заметить, что на сегодня не
существует продуктов, полностью реализующих
концепцию MDA. Тем не менее, есть целый ряд
разработок, которые реализуют основные идеи,
заложенные в эту технологию. Мы рассмотрим
детище шведской компании BoldSoft MDE Aktiebolag
– Bold for Delphi. Первая версия Bold была
выпущена в 1999 году. С тех пор продукт
значительно видоизменился и вырос как в
функциональном, так и в качественном отношении.
И сразу после выхода Delphi 7 и очередной версии
Bold продукт вместе с компанией был выкуплен
корпорацией Borland. На сегодняшний день
существуют версии этого продукта для всех версий
Delphi, начиная с Delphi 5. Мы воспользуемся
наиболее популярной версией – для Delphi 7
Architect.
С чего начать?
Давайте выясним, что же вам понадобится
установить на свой компьютер для работы и где
это взять. Прежде всего, это Delphi 7 (думаю,
что продукт в представлении не нуждается). Далее
нам понадобится непосредственно MDA средство -
Bold for Delphi. Перед установкой Bold,
желательно сначала поставить Update Delphi:
ftp://ftpd.borland.com/download/delphi/d71_updates/architect/d7_ent_upd1.exe.
А потом ставим Bold For Delphi 7 v4.0.1.0,
который можно закачать по адресу:
ftp://ftpd.borland.com/download/delphi/d71_updates/boldboft_41_for_delphi/BoldForDelphiR40D7Architect4.0.1.0.exe.
Поскольку нам придется работать с UML моделями,
то неплохо будет установить UML редактор
Rational Rose, а также поставить для него скрипт
транслитерации, что бы комфортно работать с
русскоязычной моделью. Скрипт этот можно найти
по адресу
http://mda-delphi.ru/modules.php?name=Files&d_op=get_file&files_id=16,
там же лежит и документация. Использование
Rational Rose – не является обязательным
условием для работы с Bold, поскольку имеется и
встроенный редактор модели, но я все же
предпочитаю избавлять себя от необходимости
«бегать мышкой по деревьям», а предпочитаю
видеть модель в графическом представлении. Для
этого и используем Rational Rose – достаточно
известное Case средство, хотя и стоит оно
прилично. Но мы-то честно воспользуемся триалом.
Вы можете не использовать скрипт транслитерации,
а вместо этого поставить библиотеку RBoldModel
предназначенную для осуществления поддержки
русских названий в среде Bold For Delphi (BFD) (http://mda-delphi.ru/forums/viewtopic.php?t=156).
Ставим задачу.
Итак, все необходимое для работы установлено,
и нам осталось лишь определиться с задачей,
которую мы будем решать. Конечно, что у вас есть
выданные задания, а для примера возьмем задачу
автоматизации складского учета. Естественно, что
задачу эту мы будем решать в слегка упрощенном
виде, что, тем не менее, не помешает нам понять
принципы разработки MDA приложений. Предположим,
что на складе, деятельность которого мы
автоматизируем, хранятся некоторые товары. Прием
товара на склад и его отгрузка со склада
сопровождаются соответствующими документами,
соответственно, приходной и расходной
накладными. Таким образом, имея полный перечень
накладных, мы можем получить состояние склада на
любой момент времени. Кроме того, имеется список
поставщиков и покупателей. При этом одна и та же
организация может быть как поставщиком, так и
покупателем (в бухгалтерии такие субъекты
называются контрагентами).
Каркас приложения
Далее, я опишу процедуру создания приложения
по той схеме, которую использую сам. Я считаю ее
наиболее удобной, однако, сразу оговорюсь, что
вы можете и не придерживаться строгой
последовательности действий. Тем не менее, если
вы впервые сталкиваетесь с Bold, вы можете легко
запутаться, поэтому рекомендую свое первое
Borland MDA приложение сделать именно в
соответствии с приведенной ниже схемой. Прежде
всего, давайте сделаем заготовку для нашей новой
программы. Запускаем Delphi и создаем новое
приложение. Сразу сохраняем его и настраиваем
параметры главной (и пока единственной) формы.
После этого добавляем в проект модуль данных
(Data Module). Если вы правильно выполнили
процедуру установки всех необходимых
компонентов, то на палитре компонентов вы
найдете несколько закладок, названия которых
содержат слово Bold.
На данном этапе нас интересует закладка Bold
Handles. Разместим на форме модуля данных три
компонента: BoldModel, BoldSystemTypeInfoHandle
и BoldSystemHandle и настроим их свойства
следующим образом:
object
BoldSystemHandle1: TBoldSystemHandle
SystemTypeInfoHandle = BoldSystemTypeInfoHandle1
{skiped…}
end
object BoldSystemTypeInfoHandle1:
TBoldSystemTypeInfoHandle
UseGeneratedCode = False
BoldModel = BoldModel1
{skiped…}
end
Здесь я привожу фрагмент dfm –файла с
описанием свойств компонента, ну а вы можете
использовать Object Inspector (F11).
Этот набор компонентов отвечает за связь
нашего приложения с объектным пространством,
которое будет создано автоматически на основе
модели. Также нам необходимо хранить наши данные
в каком-либо формате. Используем для этой цели
xml. Просто добавим в модуль данных компонент
BoldPersistenceHandleFileXML (закладка Bold
Persistence). И настроим его свойства так:
object
BoldPersistenceHandleFileXML1:
TBoldPersistenceHandleFileXML
FileName = '1.xml' //
произвольное имя файла
BoldModel = BoldModel1
end
Кроме того, BoldSystemHandle1 должен
ссылаться на хранилище данных:
PersistenceHandle =
BoldPersistenceHandleFileXML1
В качестве хранилища данных может быть
использована и база данных. Вы сможете составить
представление о том, какие БД можно использовать
в этих целях, внимательно изучив вкладку
BoldPersistence. Теперь свяжем наш проект с
Rational Rose. Для этого добавим компонент
BoldUMLRoseLink, настроим для него свойства
BoldModel и FileName:
FileName = 'C:\Program
Files\Borland\Delphi7\Projects\Xakep_MDA\1.mdl'
BoldModel = BoldModel1
Здесь важно, что бы файл с таким именем
существовал. Вам придется запустить Rational
Rose, создать в нем пустой файл (не используйте
Java фрэймворки - будет грузиться много лишнего)
и сохранить его. Теперь сделайте двойной щелчок
на компоненте BoldModel для того, что бы
запустить встроенный редактор модели.
Как я уже упоминал, редактор, хотя и
позволяет создать модель приложения, лишен
графических элементов. Иерархия классов
представлена в виде дерева. Нажмем кнопку
«Export via Link», для того, что бы
экспортировать заготовку модели в Rational Rose.
В дальнейшем будьте внимательны и постарайтесь
не путать кнопки «Экспорт» и «Импорт», если не
хотите потерять модель.
Строим модель
Теперь приступим к моделированию. Хотя
спецификация UML и предполагает использование
нескольких видов моделей и диаграмм для полного
описания задачи, в Bold используется только
диаграмма классов. Класс это описатель для
набора объектов с общей структурой, поведением и
отношениями. Класс содержит атрибуты и операции.
На практике класс обычно соответствует некоторой
сущности реальной системы. Давайте попробуем,
выделить сущности, для нашей задачи:
- Товар
- Приходная накладная
- Расходная накладная
- Контрагент
Создадим на диаграмме соответствующие классы,
для этого воспользуемся соответствующей кнопкой
на вертикальной панели. Названия классов смело
пишем кириллицей (если, конечно, вы не забыли
установить компоненты транслитерации). Теперь
для созданных классов зададим атрибуты
(воспользуемся пунктом “New Attribute”
выпадающего меню). Атрибуты обычно соответствуют
свойствам сущностей. Так для расходной накладной
таковыми будут номер, дата и общая стоимость
товара (сумма).
Если внимательно изучить задачу, то станет
ясно, что расходная и приходная накладные будут
иметь схожий набор атрибутов. Поэтому имеет
смысл использовать наследование. Разместим на
диаграмме класс «Накладная», куда и перенесем
общий для двух классов набор атрибутов. Класс
«Накладная» будет родительским по отношению к
классам «Расходная накладная» и «Приходная
накладная». Что бы отразить это на диаграмме
воспользуемся кнопкой «Generalization». Далее
необходимо установить связи между классами (в
терминах UML они называются ассоциации). Для
этого воспользуемся кнопкой «Undirectional
association». На практике могут использоваться
два вида ассоциаций: один-много (1-*) и
много-много (*-*). Так конкретная накладная
может быть выписана только на одного
контрагента, но на конкретного контрагента может
выписываться несколько накладных – связь 1-*. По
конкретной накладной может быть выписано
несколько товаров и конкретный вид товара может
выписываться по нескольким накладным (*-*).
Множественность ассоциаций мы можем настроить,
сделав двойной щелчок. Обратите внимание на то,
что также следует задать имя ассоциации и роли.
Роли удобно называть именами классов, на которые
данная ассоциация ссылается, а вот имя
ассоциации кириллицей лучше не называть.
Navigate для обеих ролей выставляем true.
Для завершения создания модели нам осталось
только создать классы-ассоциации. По своей сути
они напоминают связующие таблицы в реляционных
БД для реализации отношения *-*. Так при
реализации связи между классами «Расходная
накладная» и «Товар» без класса–ассоциации мы не
можем увидеть, сколько товара, и по какой цене
вносится в накладную. Для того, что бы закрепить
за ассоциацией класс-ассоциацию следует создать
новый класс и воспользоваться кнопкой
«Association Class».
Для атрибутов также следует задать тип и
начальное значение. Дважды щелкаем по классу, в
редакторе выходим на закладку со списком
атрибутов и, опять же, двойным щелчком вызываем
редактор атрибута.
Теперь, когда наша модель практически готова,
обратите внимание на то, что все названия
классов и атрибутов – русскоязычные. Те, кто
хоть немного знаком с программированием в Delphi
сразу же догадаются, что если в именах
переменных использовать символы кириллицы, то ни
к чему хорошему это не приведет. Поэтому
воспользуемся скриптом транслитерации, вызвав
его из меню (tools | Преобразование для Bold).
По окончании работы скрипта в нижней части
экрана появится отчет о проделанных
преобразованиях.
Создаем приложение
Вернемся в редактор модели Bold и нажмем
кнопку «Import via Link». Если все предыдущие
этапы были сделаны верно, то созданная в
Rational Rose модель будет импортирована в Bold.
Дерево объектов в левой части экрана обновится,
и мы сможем внести в модель некоторые
изменения.
Так, внимательно изучив диаграмму классов, вы
можете заметить, что для расходной и приходной
накладных заданны атрибуты «На кого» и «От
кого». По логике значениями этих атрибутов
должны быть реквизиты соответствующего
контрагента. Выберем в дереве классов атрибут
«На кого» класса «Расходная накладная» Поставим
для него отметку Derived (Производный) и зададим
Derivation OCL. Щелчок на кнопке возле
соответствующего поля позволяет вызвать редактор
OCL, куда мы должны вписать выражение для
вычисления атрибута.
OCL (Object Constraints Language) является
расширением языка UML. С его помощью можно
задавать вычисляемые атрибуты и осуществлять
навигацию по модели.
Так выражение konragent.imya позволяет нам
получить имя контрагента, за которым закреплена
расходная накладная. Более подробное описание
синтаксиса языка можно получить здесь. После
того, как выражения для вычисляемых атрибутов
заданы, проверим корректность модели (кнопка
Validate OCL in model), Если проверка не выявила
ошибок перейдем к созданию GUI.
Здесь я хочу сказать пару слов относительно GUI
в Bold-приложениях. К сожалению, для отображения
данных, здесь нельзя использовать обычные VCL
компоненты. Однако специальные Bold- контролы
обеспечивают достаточно удобные механизмы работы
с данными. В частности, акцент делается на
перетаскивание (drag-n-drop). Такой подход
предполагает создание несколько нетрадиционного
пользовательского интерфейса (да простят меня
консерваторы в области юзабилити). Поскольку я
ставлю цель показать, как можно создать
приложение без применения кодирования, его
интерфейс будет максимально ориентирован на
использование стандартных возможностей
Bold-контролов.
На главной форме приложения разместим четыре
панели (TPanel), таким образом, как это
представлено на рисунке. Для удобства дальнейшей
работы поставим между ними сплиттеры
(TSplitter). Обратите внимание на то, что панели
Panel3 и Panel4 размещены на Panel2.
Добавим на форму ToolBar и пару кнопок, а
также ActionList, для которого добавим два
стандартных действия из раздела Bold Actions:
BoldActivateSystemAction и BoldUpdateDBAction. В
качестве BoldSystemHandle для них зададим
BoldSystemHandle нашего приложения (он находится
в модуле данных). Выполнять эти действия поручим
кнопкам на нашем ToolBar (свойство Action).
Теперь на Panel1 разместим два элемента
управления: BoldGrid и BoldNavigator. Эти
контролы мы будем использовать для отображения
списка контрагентов и у правления им. Для
подключения источника данных мы воспользуемся
компонентом TBoldListHandle. Этот компонент
является своеобразным аналогом компонента
TDataSet в традиционных Delphi приложениях.
Настройка его достаточно проста: свойству
RootHandle присвоим значение
DM.BoldSystemHandle1 (где DM – имя модуля
данных). А значение свойства Expression введем в
редакторе OCL (вызовем его двойным щелчком).
Сначала выберем имя класса – Kontragent, а затем
добавим выражение .AllInstancess (все элементы
списка). В нижней части редактора читаем
сообщение следующего содержания:
Syntax is OK
Current type is: Collection(Kontragent)
Оно предоставляет нам информацию о том, что
выражение синтаксически правильно и показывает
выходной тип - набор элементов класса
Kontragent. Теперь подключим BoldGrid к
источнику данных. Для этого свойство BoldHandle
должно ссылаться на наш BoldListHandle. Теперь в
контекстном меню грида последовательно выберем
пункты «Clear All Columns» и «Create Default
Columns». Появившиеся столбцы грида будут
соответствовать атрибута класса Kontragent.
Подключим и BoldNavigator. Запустив приложение и
активировав систему нажатием соответствующей
кнопки, мы сможем убедиться в том, что теперь у
нас появилась возможность управлять списком
контрагентов. Перед выходом сохраним изменения,
вызвав BoldUpdateDBAction. Если мы этого не
сделаем, то при закрытии приложения получим
соответствующее уведомление.
Аналогичным образом настроим список товаров
на Panel4. На Panel3 мы разместим страничный
переключатель с двумя вкладками – “расходные” и
”приходные”. Не трудно догадаться какая
информация будет там размещена. Однако нас
интересует не полный список накладных, а
накладные для конкретного контрагента. Поэтому
RootHandle соответствующего BoldListHandle мы
настроим на BoldListHandle контрагента. Таким
образом, мы создаем цепочку дескрипторов.
Выражение (Expression) для BoldListHandle
накладных задаем так:
rashodnaya
Иными словами, мы указываем роль, для
контрагента. На выходе, как следует из сообщения
в нижней части редактора OCL выражений, получаем
список расходных накладных выписанных для
контрагента (Current type is: Collection
(Rashodnaya_nakladnaya)). Таким же образом
настраиваем и второй грид на закладке. В нем мы
будем отображать детализацию расходной, т.е.
сколько товара и по какой цене отпускается. К
каждому BoldListHandle мы подключим BoldGrid
(редактируем свойство BoldHandle). Для тех
Handle’ов, которые отвечают за классы Товар,
Расходная Накладная, Приходная Накладная и
Контрагент мы подключим еще и BoldNavigator.
Добавление и удаление записей в списки
товаров, контрагентов и накладных мы можем
осуществлять, используя соответствующие
BoldNavigator’ы. Нам осталось только “научить”
нашу программу добавлять товар в накладные. Для
этого мы используем автоформы. Автоформы –
специальные формы, которые генерируются
автоматически и содержат в себе детальную
информацию об объекте. Размещаем компонент
MDARuAF на форму и настраиваем его следующим
образом:
IniFile = 'a.ini'
Modal = False
AutoFormStyle = fsStayOnTop
TabStyle = tsTabs
GridsFlat = False
NavigationsFlat = False
GridAutoConnect = True
Этот компонент (к слову написанный вашим
покорным слугой) просто позволяет сделать работу
с автоформами немного удобнее, например он дает
возможность сохранить положение и размер формы
после ее закрытия в ini-файли или поменять
название атрибута (по умолчанию мы увидим
транслит латиницей). Теперь двойной щелчок по
записи любого грида приведет к вызову формы
детализации соответствующего объекта.
Так форма, приведенная на скриншоте,
отображает не только все атрибуты выбранной
расходной накладной, но и все связанные с ней
объекты – перечень товаров и расшифровку
расходной. Если необходимо добавить товар в
расходную накладную, то достаточно просто
перетащить нужный объект из списка товаров
(справа внизу на главной форме нашего
приложения) на вкладку «товар», а затем перейти
на вкладку «Расшифровка расходной» и указать
количество и цену товара. Как видите, все просто
и удобно.
На этом можно бы было и остановиться. В
принципе это приложение выполняет все
возлагаемые на него функции и можно смело
садиться за написание текста курсовой
(украшением которого, безусловно, станет не
только программа, но и диаграмма классов). Вы
можете самостоятельно добавить в приложение
некоторое функции, такие, например, как
вычисление количества товара на складе. А можете
и оставить все как есть.
Тем не менее, как я и обещал, не было
написано ни строчки кода. И, конечно же, многие
из вас отнесутся с недоверием к описанной
технологии. Однако не следует думать, что
возможности Bold for Delphi ограничиваются тем,
что было описано в этом маленьком примере.
Напротив, с помощью Bold можно создавать
достаточно сложные проекты, содержащие десятки,
а то и сотни классов.
И, конечно же, в более сложных проектах не
обойтись и без «ручного» кодирования. Более
того, описанная технология приемлема не для
всяких задач. Однако Bold предоставляет ряд
очевидных преимуществ, которые позволяют
существенно (по заверению Borland в 5 - 10 раз)
ускорить процесс разработки.
Сегодня разработчики Bold практически
отказались от технической поддержки своего
продукта, хотя и регулярно обновляют его. Кроме
того, практически все исходники находятся в
открытом доступе. Но это не означает, что
Borland отказался от идеи создания совершенного
MDA средства. Несколько месяцев назад вышла
очередная версия Borland ECO – инструмента
разработки для .Net, написанного авторами Bold.
О работе с ECO я планирую рассказать в следующей
статье.
Исходники:
Xakep_MDA.rar