учебники, программирование, основы, введение в,

 

Проектирование реляционных баз данных с использованием семантических моделей: диаграммы классов языка UML

Введение
Языку объектно-ориентированного моделирования UML (Unified Modeling Language) посвящено великое множество книг, многие из которых переведены на русский язык (а некоторые и написаны российскими авторами). Язык UML разработан и развивается консорциумом OMG (Object Management Group) и имеет много общего с объектными моделями, на которых основана технология распределенных объектных систем CORBA, и объектной моделью ODMG (Object Data Management Group).
UML позволяет моделировать разные виды систем: чисто программные, чисто аппаратные, программно-аппаратные, смешанные, явно включающие деятельность людей и т. д. Даже если бы мы ограничились возможностями использования UML для проектирования программных информационных систем, это слишком далеко увело бы нас от основной темы курса.
Но, помимо прочего, язык UML активно применяется для проектирования реляционных БД. Для этого используется небольшая часть языка (диаграммы классов), да и то не в полном объеме. С точки зрения проектирования реляционных БД модельные возможности не слишком отличаются от возможностей ER-диаграмм. Но все же мы кратко опишем диаграммы классов UML, поскольку их использование при проектировании реляционных БД позволяет оставаться в общем контексте UML и применять другие виды диаграмм для проектирования приложений баз данных.
Основные понятия диаграмм классов UML
Диаграммой классов в терминологии UML называется диаграмма, на которой показан набор классов (и некоторых других сущностей, не имеющих явного отношения к проектированию БД), а также связей между этими классами.Кроме того, диаграмма классов может включать комментарии и ограничения. Ограничения могут неформально задаваться на естественном языке или же могут формулироваться на языке объектных ограничений OCL (Object Constraints Language).Чуть позже мы обсудим эту тему более подробно.
Классы, атрибуты, операции
Классом называется именованное описание совокупности объектов с общими атрибутами, операциями, связями и семантикой. Графически класс изображается в виде прямоугольника. У каждого класса должно быть имя (текстовая строка), уникально отличающее его от всех других классов. При формировании имен классов в UML допускается использование произвольной комбинации букв, цифр и даже знаков препинания. Однако на практике рекомендуется использовать в качестве имен классов короткие и осмысленные прилагательные и существительные, каждое из которых начинается с заглавной буквы. Примеры описания классов показаны на.
Атрибутом класса называется именованное свойство класса, описывающее множество значений, которые могут принимать экземпляры этого свойства. Класс может иметь любое число атрибутов (в частности, не иметь ни одного атрибута). Свойство, выражаемое атрибутом, является свойством моделируемой сущности, общим для всех объектов данного класса. Так что атрибут является абстракцией состояния объекта. Любой атрибут любого объекта класса должен иметь некоторое значение.
Имена атрибутов представляются в разделе класса, расположенном под именем класса. Хотя UML не накладывает ограничений на способы создания имен атрибутов (имя атрибута может быть произвольной текстовой строкой), на практике рекомендуется использовать короткие прилагательные и существительные, отражающие смысл соответствующего свойства класса. Первое слово в имени атрибута рекомендуется писать с прописной буквы, а все остальные слова – с заглавной. Пример описания класса с указанными атрибутами показан на.
Операцией класса называется именованная услуга, которую можно запросить у любого объекта этого класса. Операция – это абстракция того, что можно делать с объектом. Класс может содержать любое число операций (в частности, не содержать ни одной операции). Набор операций класса является общим для всех объектов данного класса.
Операции класса определяются в разделе, расположенном ниже раздела с атрибутами. При этом можно ограничиться только указанием имен операций, оставив детальную спецификацию выполнения операций на более поздние этапы моделирования. Для именования операций рекомендуется использовать глагольные формы, соответствующие ожидаемому поведению объектов данного класса. Описание операции может также содержать ее сигнатуру, т. е. имена и типы всех параметров, а если операция является функцией, то и тип ее значения. Класс Человек с определенными операциями показан на. Для класса Человек мы определили три операции: выдатьВозраст, сохранитьТекущийДоход, выдатьОбщийДоход. В операции выдатьВозраст используются значение атрибута датаРождения и значение текущей даты. Операция сохранитьТекущийДоход позволяет зафиксировать в состоянии объекта сумму и дату поступления дохода данного человека. Операция выдатьОбщийДоход выдает суммарный доход данного человека за указанное время. Заметим, что состояние объекта меняется при выполнении только второй операции. Результаты первой и третьей операций формируются на основе текущего состояния объекта.

Категории связей. Связь-зависимость
В диаграмме классов могут участвовать связи трех разных категорий: зависимость (dependency), обобщение (generalization) и ассоциация (association). При проектировании реляционных БД наиболее важны вторая и третья категории связей, поэтому о связях-зависимостях будет сказано только самое основное.
Зависимостью называют связь по применению, когда изменение в спецификации одного класса может повлиять на поведение другого класса, использующего первый класс. Чаще всего зависимости применяют в диаграммах классов, чтобы отразить в сигнатуре операции одного класса тот факт, что параметром этой операции могут быть объекты другого класса. Понятно, что если интерфейс второго класса изменяется, это влияет на поведение объектов первого класса. Простой пример диаграммы классов со связью-зависимостью показан на.
Зависимость показывается прерывистой линией со стрелкой, направленной к классу, от которого имеется зависимость. чевидно, что связи-зависимости существенны для объектно-ориентированных систем (в том числе и для ООБД). При проектировании реляционных БД непонятно, что делать с зависимостями (как воспользоваться этой информацией в реляционной БД?).
Связи-обобщения и механизм наследования классов в UML
Связью-обобщением называется связь между общей сущностью, называемой суперклассом, или родителем, и более специализированной разновидностью этой сущности, называемой подклассом, или потомком. Обобщения иногда называют связями «is a», имея в виду, что класс-потомок является частным случаем класса-предка. Класс-потомок наследует все атрибуты и операции класса-предка, но в нем могут быть определены дополнительные атрибуты и операции.
Объекты класса-потомка могут использоваться везде, где могут использоваться объекты класса-предка. Это свойство называют полиморфизмом по включению, имея в виду, что объекты потомка можно считать включаемыми во множество объектов класса-предка. Графически обобщения изображаются в виде сплошной линии с большой незакрашенной стрелкой, направленной к суперклассу. В качестве первой иллюстрации, приведенной на, воспользуемся классификацией летательных аппаратов с из предыдущей лекции. На показан пример иерархии одиночного наследования: у каждого подкласса имеется только один суперкласс.
Одиночное наследование является достаточным в большинстве случаев применения связи-обобщения. Однако в UML допускается и множественное наследование, когда один подкласс определяется на основе нескольких суперклассов. В качестве одного из разумных (не слишком распространенных) примеров рассмотрим диаграмму классов на (для упрощения диаграммы имена атрибутов и операций указывать не будем).
На этой диаграмме классы Студент и Преподаватель порождены из одного суперкласса ЧеловекИзУниверситета. Вообще говоря, к классу Студент относятся те объекты класса ЧеловекИзУниверситета, которые соответствуют студентам, а к классу Преподаватель – объекты класса ЧеловекИзУниверситета, соответствующие преподавателям. Но, как это часто случается, многие студенты уже в студенческие годы начинают преподавать, так что могут существовать такие два объекта классов Студент и Преподаватель, которым соответствует один объект класса ЧеловекИзУниверситета. Итак, среди объектов класса Студент могут быть преподаватели, а некоторые преподаватели могут быть студентами. Тогда мы можем определить класс СтудентПреподаватель путем множественного наследования от суперклассов Студент и Преподаватель. Объект класса СтудентПреподаватель обладает всеми свойствами и операциями классов Студент и Преподаватель и может быть использован везде, где могут применяться объекты этих классов. Так что полиморфизм по включению продолжает работать. Следует отметить, что множественное наследование, помимо того что не слишком часто требуется на практике, порождает ряд проблем, из которых одной из наиболее известных является проблема именования атрибутов и операций в подклассе, полученном путем множественного наследования. Например, предположим, что при образовании подклассов Студент и Преподаватель в них обоих был определен атрибут с именем номерКомнаты. Очень вероятно, что для объектов класса Студент значениями этого атрибута будут номера комнат в студенческом общежитии, а для объектов класса Преподаватель – номера служебных кабинетов. Как быть с объектами класса СтудентПреподаватель, для которых существенны оба одноименных атрибута (у студента-преподавателя могут иметься и комната в общежитии, и служебный кабинет)? На практике применяется одно из следующих решений:

  1. запретить образование подкласса СтудентПреподаватель, пока в одном из суперклассов не будет произведено переименование атрибута номерКомнаты;
  2. наследовать это свойство только от одного из суперклассов, так что, например, значением атрибута номерКомнаты у объектов класса СтудентПреподаватель всегда будут номера служебных кабинетов;
  3. унаследовать в подклассе оба свойства, но автоматически переименовать оба атрибута, чтобы прояснить их смысл; назвать их, например, номерКомнатыСтудента и номерКомнатыПреподавателя.

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

Связи-ассоциации: роли, кратность, агрегация
Ассоциацией называется структурная связь, показывающая, что объекты одного класса некоторым образом связаны с объектами другого или того же самого класса. Допускается, чтобы оба конца ассоциации относились к одному классу. В ассоциации могут связываться два класса, и тогда она называется бинарной. Допускается создание ассоциаций, связывающих сразу n классов (они называются n-арными ассоциациями). Графически ассоциация изображается в виде линии, соединяющей класс сам с собой или с другими классами.
С понятием ассоциации связаны четыре важных дополнительных понятия: имя, роль, кратность и агрегация. Во-первых, ассоциации может быть присвоено имя, характеризующее природу связи. Смысл имени уточняется с помощью черного треугольника, который располагается над линией связи справа или слева от имени ассоциации. Этот треугольник указывает направление чтения имя связи. Пример именованной ассоциации показан на. Треугольник показывает, что именованная ассоциация должна читаться как «Студент учится в Университете».
Другим способом именования ассоциации является указание роли каждого класса, участвующего в этой ассоциации. Роль класса, как и имя конца связи в ER-модели, задается именем, помещаемым под линией ассоциации ближе к данному классу. На показаны две ассоциации между классами Человек и Университет, в которых эти классы играют разные роли. Как мы видим, объекты класса Человек могут выступать в роли РАБОТНИКОВ при участии в ассоциации, в которой объекты класса Университет играют роль НАНИМАТЕЛЯ. В другой ассоциации объекты класса Человек играют роль СТУДЕНТА, а объекты класса УНИВЕРСИТЕТ – роль ОБУЧАЮЩЕГО.
В общем случае, для ассоциации могут задаваться и ее собственное имя, и имена ролей классов. Это связано с тем, что класс может играть одну и ту же роль в разных ассоциациях, так что в общем случае пара имен ролей классов не идентифицирует ассоциацию. С другой стороны, в простых случаях, когда между двумя классами определяется только одна ассоциация, можно вообще не связывать с ней дополнительные имена.
Кратностью (multiplicity) роли ассоциации называется характеристика, указывающая, сколько объектов класса с данной ролью может или должно участвовать в каждом экземпляре ассоциации (в UML экземпляр ассоциации называется соединением – link, но мы не будем здесь использовать этот термин, чтобы не создавать путаницу – все-таки трудно одновременно говорить про связи, ассоциации и соединения, имея в виду разные понятия). Наиболее распространенным способом задания кратности роли ассоциации является указание конкретного числа или диапазона. Например, указание «1» говорит о том, что каждый объект класса с данной ролью должен участвовать в некотором экземпляре данной ассоциации, причем в каждом экземпляре ассоциации может участвовать ровно один объект класса с данной ролью. Указание диапазона «0..1» говорит о том, что не все объекты класса с данной ролью обязаны участвовать в каком-либо экземпляре данной ассоциации, но в каждом экземпляре ассоциации может участвовать только один объект. Аналогично, указание диапазона «1..*» говорит о том, что все объекты класса с данной ролью должны участвовать в некотором экземпляре данной ассоциации, и в каждом экземпляре ассоциации должен участвовать хотя бы один объект (верхняя граница не задана). Толкование диапазона «0..*» является очевидным расширением случая «0..1».
В более сложных (но крайне редко встречающихся на практике) случаях определения кратности можно использовать списки диапазонов. Например, список «2, 4..6, 8..*» говорит о том, что все объекты класса с указанной ролью должны участвовать в некотором экземпляре данной ассоциации, и в каждом экземпляре ассоциации должны участвовать два, от четырех до шести или более семи объектов класса с данной ролью.
На диаграмме классов с показано, что произвольное (может быть, нулевое) число людей являются сотрудниками произвольного числа университетов. Каждый университет обучает произвольное (может быть, нулевое) число студентов, но каждый студент может быть студентом только одного университета.
Обычная ассоциация между двумя классами характеризует связь между равноправными сущностями: оба класса находятся на одном концептуальном уровне. Но иногда в диаграмме классов требуется отразить тот факт, что ассоциация между двумя классами имеет специальный вид «часть-целое». В этом случае класс «целое» имеет более высокий концептуальный уровень, чем класс «часть». Ассоциация такого рода называется агрегатной. Графически агрегатные ассоциации изображаются в виде простой ассоциации с незакрашенным ромбом на стороне класса-«целого». Простой пример агрегатной ассоциации показан на.
Объектами класса Аудитория являются студенческие аудитории, в которых проходят занятия. В каждой аудитории должны быть установлены парты. Поэтому в некотором смысле класс Парта является «частью» класса Аудитория. Мы умышленно сделали роль класса Парта необязательной, поскольку могут существовать аудитории без парт (например, класс для занятий танцами) и некоторые парты могут находиться на складе. Обратите внимание, что, хотя аудитории, не оснащенные партами, как правило, непригодны для занятий, объекты классов Аудитория и Парта существуют независимо. Если некоторая аудитория ликвидируется, то находящиеся в ней парты не уничтожаются, а переносятся на склад.
Бывают случаи, когда связь «части» и «целого» настолько сильна, что уничтожение «целого» приводит к уничтожению всех его «частей». Агрегатные ассоциации, обладающие таким свойством, называются композитными, или просто композициями. При наличии композиции объект-часть может быть частью только одного объекта-целого (композита). При обычной агрегатной ассоциации «часть» может одновременно принадлежать нескольким «целым». Графически композиция изображается в виде простой ассоциации, дополненной закрашенным ромбом со стороны «целого». Пример композитной агрегатной ассоциации показан на.
Любой факультет является частью одного университета, и ликвидация университета приводит к ликвидации всех существующих в нем факультетов (хотя во время существования университета отдельные факультеты могут ликвидироваться и создаваться).
Заметим, что в контексте проектирования реляционных БД агрегатные и в особенности композитные ассоциации влияют только на способ поддержки ссылочной целостности. В частности, композитная связь является явным указанием на то, что ссылочная целостность между «целым» и «частями» должна поддерживаться путем каскадного удаления частей при удалении целого. Подробнее способы поддержки ссылочной целостности в SQL-ориентированных БД рассматриваются в следующих лекциях.
При наличии простой ассоциации между двумя классами (например, ассоциации между классами Студент и Университет с) предполагается возможность навигации между объектами, входящими в один экземпляр ассоциации. Если известен конкретный объект-студент, то должна обеспечиваться возможность узнать соответствующий объект-университет. Если известен конкретный объект-университет, то должна обеспечиваться возможность узнать все соответствующие объекты-студенты. Другими словами, если не оговорено иное, то навигация по ассоциации может проводиться в обоих направлениях. Однако бывают случаи, когда желательно ограничить направление навигации для некоторых ассоциаций. В этом случае на линии ассоциации ставится стрелка, указывающая направление навигации. Пример показан на.
В библиотеке должно содержаться некоторое количество книг, и каждая книга должна принадлежать некоторой библиотеке. С точки зрения библиотечного хозяйства разумно иметь возможность найти книгу в библиотеке, т. е. произвести навигацию от объекта-библиотеки к связанным с ним объектам-книгам. Однако вряд ли потребуется по данному экземпляру книги узнать, в какой библиотеке она находится

Ограничения целостности и язык OCL

Как уже отмечалось, в диаграммах классов могут указываться ограничения целостности, которые должны поддерживаться в проектируемой БД. В UML допускаются два способа определения ограничений: на естественном языке и на языке OCL. На показана простая диаграмма классов Студент и Университет с ограничением, выраженным на естественном языке.
В данном случае накладывается ограничение на состояние объектов классов Студент и Университет, входящих в один экземпляр ассоциации. Объект класса Студент может входить в экземпляр связи с объектом класса Университет только при условии, что размер стипендии данного студента находится в диапазоне, допустимом в данном университете.

Общая характеристика языка OCL

Более точный и лаконичный способ формулировки ограничений обеспечивает язык OCL (Object Constraints Language). Вот общая характеристика этого языка.
Из языка UML в OCL заимствованы, в первую очередь, следующие концепции:

  • класс, атрибут, операция;
  • объект (экземпляр класса);
  • ассоциация;
  • тип данных (включая набор предопределенных типов Boolean, Integer, Real и String);
  • значение (экземпляр типа данных).

Для понимания языка OCL существенны определяемые в UML традиционные для объектных моделей данных различия между объектом некоторого класса и значением некоторого типа:

  • объект обладает уникальным идентификатором и может сравниваться с другими объектами только по значению идентификатора; следствием этого является возможность определения операций над множествами объектов в терминах их идентификаторов;
  • объект может быть ассоциирован через бинарную связь с другими объектами, что позволяет определить в OCL операцию перехода от данного объекта к связанным с ним объектам;
  • в то же время значение является «чистым значением» в том смысле, что:
    • при сравнении двух значений проверяются сами эти значения;
    • кроме того, значения не могут участвовать в связях, поскольку понятие связи определено только для объектов классов.

В дополнение к скалярным типам данных, заимствованным из UML, в OCL предопределены структурные типы, которые являются разновидностями типов коллекций (collection):

  • математическое множество (set), неупорядоченная коллекция, не содержащая одинаковых элементов;
  • мультимножество (bag), неупорядоченная коллекция, которая может содержать повторяющиеся элементы-дубликаты;
  • последовательность (sequence), упорядоченная коллекция, которая может содержать элементы-дубликаты.

В OCL элементами каждого из трех типов коллекций могут быть либо объекты, либо значения.
Язык OCL предназначен, главным образом, для определения ограничений целостности данных, соответствующих модели, которая представлена в терминах диаграммы классов UML. OCL может применяться для определения ограничений, описывающих пред- и постусловия операций классов, и ограничений, представляющих собой инварианты классов. При проектировании реляционных баз данных возможность определения пред- и постусловий операций вряд ли может оказаться существенной. С точки зрения определения ограничений целостности баз данных более важны средства определения инвариантов классов.

Инвариант класса

Под инвариантом класса в OCL понимается условие, которому должны удовлетворять все объекты данного класса. Если говорить более точно, инвариант класса – это логическое выражение, вычисление которого должно давать true при создании любого объекта данного класса и сохранять истинное значение в течение всего времени существования этого объекта. При определении инварианта требуется указать имя класса и выражение, определяющее инвариант указанного класса. Синтаксически это выглядит следующим образом:

context <class_name> inv:
<OCL-выражение>

Здесь <class-name> является именем класса, для которого определяется инвариант, inv – ключевое слово, говорящее о том, что определяется именно инвариант, а не ограничение другого вида, и context – ключевое слово, которое говорит о том, что контекстом следующего после двоеточия OCL-выражения являются объекты класса <class-name>, т. е. OCL-выражение должно принимать значение true для всех объектов этого класса.
Заметим, что OCL является типизированным языком, поэтому у каждого выражения имеется некоторый тип. Естественно, что OCL-выражение в инварианте класса должно быть логического типа.
В общем случае OCL-выражение в определении инварианта основывается на композиции операций, которым посвящена большая часть определения языка. В спецификации языка эти операции условно разделены на следующие группы:

  • операции над значениями предопределенных в UML (скалярных) типов данных;
  • операции над объектами;
  • операции над множествами;
  • операции над мультимножествами;
  • операции над последовательностями.

Последовательно обсудим эти группы операций.

Операции над значениями предопределенных типов данных

Полагая очевидной семантику предопределенных скалярных типов данных и операций над ними, ограничимся лишь их перечислением. В OCL поддерживаются следующие заимствованные из определения UML скалярные типы данных: Boolean, Integer, Real и String.

Операции над объектами

В OCL определены три операции над объектами:

  • получение значения атрибута;
  • переход по соединению,
  • вызов операции класса (последняя операция для целей проектирования реляционных БД несущественна).

Для записи этих трех операций используется «точечная нотация». Например, результатом выражения вида

<объект>.<имя атрибута>

является текущее значение атрибута с именем имя атрибута, если объект имеет такой атрибут. В противном случае использование подобного выражения приводит к возникновению ошибки типа.
Результатом применения к объекту операции перехода по соединению (экземпляру связи-ассоциации) является коллекция, содержащая все объекты, которые ассоциированы с данным объектом через указываемое соединение. Это соединение идентифицируется именем роли, противоположной по отношению к данному объекту. Таким образом, синтаксис выражения перехода по соединению следующий:

<объект>.<имя роли, противоположенной по отношению к объекту>

Операции над множествами, мультимножествами и последовательностями

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

<коллекция>  <имя операции> (<список фактических параметров>)
Операция select

В OCL определены три одноименных операции select, которые обрабатывают заданное множество, мультимножество или последовательность на основе заданного логического выражения над элементами коллекции. Результатом каждой операции является новое множество, мультимножество или последовательность, соответственно, из тех элементов входной коллекции, для которых результатом вычисления логического выражения является true.

Операция collect

Аналогично набору операций select, в OCL определены три операции collect, параметрами которых являются множество, мультимножество или последовательность и некоторое выражение над элементами соответствующей коллекции. Результатом является мультимножество для операций collect, определенных над множествами и мультимножествами, и последовательность для операции collect, определенной над последовательностью. При этом результирующая коллекция соответствующего типа (коллекция значений или объектов) состоит из результатов применения выражения к каждому элементу входной коллекции. Операция collect используется, главным образом, в тех случаях, когда от заданной коллекции объектов требуется перейти к некоторой другой коллекции объектов, которые ассоциированы с объектами исходной коллекции через некоторое соединение. В этом случае выражение над элементом исходной коллекции основывается на операции перехода по соединению.

Операции exists, forAll, size

В OCL определены три одноименных операции exists над множеством, мультимножеством и последовательностью, дополнительным параметром которых является логическое выражение. В результате каждой из этих операций выдается true в том и только в том случае, когда хотя бы для одного элемента входной коллекции значением логического выражения является true. В противном случае результатом операции является false. Операции forAll отличаются от операций exist тем, что в результате каждой из них выдается true в том и только в том случае, когда для всех элементов входной коллекции результатом вычисления логического выражения является true. В противном случае результатом операции будет false. Операция size применяется к коллекции и выдает число содержащихся в ней элементов.

Операции union, intersect, symmetricDifference

Параметрами двуместных операций union, intersect, symmetricDifference являются две коллекции, причем в OCL операции определены почти для всех возможных комбинаций типов коллекции. Не будем рассматривать все определения этих операций и кратко упомянем только две из них. Результатом операции union, определенной над множеством и мультимножеством, является мультимножество, т. е. из результата объединения таких двух коллекций дубликаты не исключаются. Результатом же операции union, определенной над двумя множествами, является множество, т. е. в этом случае возможные дубликаты должны быть исключены.

Примеры инвариантов

В заключение обзора языка OCL приведем примеры четырех инвариантов, выраженных на этом языке. Будем основываться на диаграмме классов, показанной на.

context Служащий inv:
self.возраст >18 and self.возраст < 100

Условие инварианта накладывает требуемое ограничение на значения атрибута возраст, определенного в классе Служащий. В условном выражении инварианта ключевое слово self обозначает текущий объект класса-контекста инварианта. Можно считать, что при проверке данного условия будут перебираться существующие объекты класса Служащий, и для каждого объекта будет проверяться, что значения атрибута возраст находятся в пределах заданного диапазона. Ограничение удовлетворяется, если условное выражение принимает значение true для каждого объекта класса-контекста.

context Отдел inv:
self.номер  5 or 
self.служащий  select (возраст  30)  size () = 0

В этом случае условное выражение инварианта будет вычисляться для каждого объекта класса Отдел. Подвыражение справа от операции or вычисляется слева направо. Сначала вычисляется подвыражение self.служащий, значением которого является множество объектов, соответствующих служащим, которые работают в текущем отделе. Далее к этому множеству применяется операция select (возраст 30), в результате которой вырабатывается множество объектов, соответствующих служащим текущего отдела, возраст которых не превышает 30 лет. Значением операции size () является число объектов в этом множестве. Все выражение принимает значение true, если последняя операция сравнения «=0» вырабатывает значение true, т. е. если в текущем отделе нет сотрудников младше 31 года. Ограничение в целом удовлетворяется только в том случае, если значением условия инварианта является true для каждого отдела.
Тот же инвариант можно сформулировать в контексте класса Сотрудник:

context Сотрудник inv:
self.возраст > 30 or self.отдел.номер < 5

Здесь следует обратить внимание на подвыражение self.отдел.номер > 5. Поскольку отдел – это имя роли соединения, значением подвыражения self.отдел является коллекция (множество). Но кратность роли отдел равна единице, т. е. каждому объекту служащего соответствует в точности один объект отдела. Поэтому в OCL допускается сокращенная запись операции self.отдел.номер, значением которой является номер отдела текущего служащего.

context Отдел inv:
self.служащий  exists (должность = "manager") and 
self.компания.годОснования  self.годОснования

Здесь должность – атрибут класса Сотрудники, а атрибуты с именем годОснования имеются и у класса Отдел, и у класса Компания. В условном выражении этого инварианта подвыражение self.служащий exists (должность = "manager") эквивалентно выражению self.служащий select (должность = "manager") size () > 1. Если бы в ограничении мы потребовали, чтобы у каждого отдела был только один менеджер, то следовало бы написать ... size () = 1, и это было бы не эквивалентно варианту с exists.
Обратите внимание, что в этом случае снова законным является подвыражение self.компания.годОснования, поскольку кратность роли компания в ассоциации классов Отдел и Компания равна единице.

context Компания inv:
self.отдел  collect (служащие)  size ( ) < 1000

Здесь полезно обратить внимание на использование операции collect. Проследим за вычислением условного выражения. В нашем случае в классе Компания всего один объект, и он сразу становится текущим. В результате выполнения операции self.отдел будет получено множество объектов, соответствующих всем отделам компании. При выполнении операции collect (служащие) для каждого объекта-отдела по соединению с объектами класса СЛУЖАЩИЕ будет образовано множество объектов-служащих данного отдела, а в результате будет образовано множество объектов, соответствующих всем служащим всех отделов компании, т. е. всем служащим компании.

Плюсы и минусы использования языка OCL при проектировании реляционных баз данных

Плюсы и минусы использования языка OCL при проектировании реляционных БД очевидны. Язык позволяет формально и однозначно (без двусмысленностей, свойственных естественным языкам) определять ограничения целостности БД в терминах ее концептуальной схемы. Скорее всего, наличие подобной проектной документации будет полезным для сопровождения БД, даже если придется преобразовывать инварианты OCL в ограничения целостности SQL вручную.
К отрицательным сторонам использования OCL относится, прежде всего, сложность языка и неочевидность некоторых его конструкций. Кроме того, строгость синтаксиса и линейная форма языка в некотором роде противоречат наглядности и интуитивной ясности диаграммной части UML. Да, в инвариантах OCL используются те же понятия и имена, что и в соответствующей диаграмме классов, но используются совсем в другой манере. И последнее. Трудно доказать или опровергнуть как предположение, что на языке OCL можно выразить любое ограничение целостности, которое можно определить средствами SQL, так и утверждение, что на языке OCL нельзя выразить такой инвариант, для которого окажется невозможным сформулировать эквивалентное ограничение целостности на языке SQL. Лично мне неизвестны работы, в которых бы сравнивалась выразительная мощность этих языков в связи с ограничениями целостности реляционных БД.


Получение схемы реляционной базы данных из диаграммы классов UML
Если не обращать внимания на различия в терминологии, то здесь выполняются практически те же шаги, что и в случае преобразования в схему реляционной БД ER-диаграммы. Поэтому ограничимся только некоторыми рекомендациями, специфичными для диаграмм классов.
Рекомендация 1. Прежде чем определять в классах операции, подумайте, что вы будете делать с этими определениями в среде целевой РСУБД. Если в этой среде поддерживаются хранимые процедуры, то, возможно, некоторые операции могут быть реализованы именно с помощью такого механизма. Но если в среде РСУБД поддерживается механизм определяемых пользователями функций, возможно, он окажется более подходящим.
Рекомендация 2. Помните, что сравнительно эффективно в РСУБД реализуются только ассоциации видов «один ко многим» и «многие ко многим». Если в созданной диаграмме классов имеются ассоциации «один к одному», следует задуматься о целесообразности такого проектного решения. Реализация в среде РСУБД ассоциаций с точно заданными кратностями ролей возможна, но требует определения дополнительных триггеров, выполнение которых понизит эффективность.
Рекомендация 3. Для технологии реляционных БД агрегатные и в особенности композитные ассоциации неестественны. Подумайте о том, что вы хотите получить в реляционной БД, объявив некоторую ассоциацию агрегатной. Скорее всего, ничего.
Рекомендация 4. В спецификации UML говорится о том, что, определяя однонаправленные связи, вы можете способствовать эффективности доступа к некоторым объектам. Для технологии реляционных баз данных поддержка такого объявления вызовет дополнительные накладные расходы и тем самым снизит эффективность.
Рекомендация 5. Не злоупотребляйте возможностями OCL.
Диаграммы классов UML – это мощный инструмент для создания концептуальных схем баз данных, но, как известно, все хорошо в меру.
Заключение
Нельзя сказать, что проектирование баз данных на основе семантических моделей в любом случае ускоряет и/или упрощает процесс проектирования. Все зависит от сложности предметной области, квалификации проектировщика и качества вспомогательных программных средств. Но так или иначе этап диаграммного моделирования обеспечивает следующие преимущества:
  • на раннем этапе проектирования до привязки к конкретной РСУБД проектировщик может обнаружить и исправить логические недочеты проекта, руководствуясь наглядным графическим представлением концептуальной схемы;
  • окончательный вид концептуальной схемы, полученной непосредственно перед переходом к формированию реляционной схемы, а может быть, и промежуточной версии концептуальной схемы, должен стать частью документации целевой реляционной БД; наличие этой документации очень полезно для сопровождения и, в особенности, для изменения схемы БД в связи с изменившимися требованиями;
  • при использовании CASE-средств концептуальное моделирование БД может стать частью всего процесса проектирования целевой информационной системы, что должно способствовать правильной структуризации процесса, эффективности и повышению качества проекта в целом.

Мы также хотели показать, что в контексте проектирования реляционных БД структурные методы проектирования, основанные на использовании ER-диаграмм, и объектно-ориентированные методы, основанные на использовании языка UML, различаются, главным образом, лишь терминологией. ER-модель концептуально проще UML, в ней меньше понятий, терминов, вариантов применения. И это понятно, поскольку разные варианты ER-моделей разрабатывались именно для поддержки проектирования реляционных БД, и ER-модели почти не содержат возможностей, выходящих за пределы реальных потребностей проектировщика реляционной БД.
Язык UML принадлежит объектному миру. Этот мир гораздо сложнее (если угодно, непонятнее, запутаннее) реляционного мира. Поскольку UML может использоваться для унифицированного объектно-ориентированного моделирования всего чего угодно, в этом языке содержится масса различных понятий, терминов и вариантов использования, избыточных с точки зрения проектирования реляционных БД. Если вычленить из общего механизма диаграмм классов то, что действительно требуется для проектирования реляционных БД, то мы получим в точности ER-диаграммы с другой нотацией и терминологией.
Поэтому выбор конкретной концептуальной модели – это вопрос вкуса и сложившихся обстоятельств. Понятно, что если в организации уже имеется сложившаяся инфраструктура проектирования приложений, то разумно продолжать ею пользоваться до тех пор, пока это не станет тормозом. При построении же новой инфраструктуры стратегические соображения высшего руководства компании имеют больший вес, чем предпочтения технических специалистов, хотя эти предпочтения тоже обязательно должны учитываться.

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика