Select order_num, cust_num, prod_id, qty, date_order 2 страница
Можно считать, что объекты имеют поля (слоты), в которых размещены значения. Такими значениями могут быть целые числа, строки или массивы, ссылки на другие объекты, а также методы, т. е. функции, применяемые к объектам.
Мы сосредоточимся на абстрактных понятиях класса и его свойств, не вдаваясь в детали реализации типа упорядочивания полей записи и даже в реальное представление объекта.
Определяя проект классов ODL, будем описывать свойства следующих видов, перечисление которых приводится далее.
1. Атрибуты – свойства, типы которых строятся из исходных типов, например целых чисел или строк. Характерно то, что атрибут имеет тип, не включающий в себя ни одного класса. В ODL типы атрибутов ограничены.
2. Связи – свойства, типом которых являются ссылка на объект некоторого класса или набор (например, множество) таких ссылок.
3. Методы – функции, которые можно применить к объектам класса. В данном изложении применение методов не рассматривается.
4.1.2. Описания классов
Описания класса в ODL в их простейшей форме состоят из следующих элементов:
1. Ключевого слова interface.
2. Имени интерфейса (т.е. класса).
3. Списка свойств класса, заключенного в скобки. Напоминаем, что свойства – это атрибуты, связи и методы.
Простая форма описания интерфейса:
interface <имя>{
<список свойств>}
4.1.3. Атрибуты в ODL
Свойства объектов называются атрибутами. Эти свойства описывают определенные аспекты объекта, связывая с ним значение некоторого простого типа. Например, все объекты студент могут иметь атрибут имя, типом которого является строка, а значением – имя данного человека. Эти объекты могут иметь также атрибут дата_рождения, являющийся тройкой целых чисел (т.е. структурой записи), выражающей год, месяц и день рождения данного студента.
Пример 4.1.Нижеприведено ODL-описание класса изделий ателье. Здесь оно относительно простое; позже мы расширим его.
1) interface Изделие {
2)attribute string назв_изделия;
3) attribute integer размер;
4) attribute enum Материал{ткань, мех, кожа}
тип_материала;};
Здесь и далее предполагается, что в именах допускаются кириллические символы. Данный пример чисто иллюстративный, для упрощения указывается только один размер и допускается использование только трех типов материалов.
Строка 1 описывает Изделие как класс. Ключевое слово interface используется в ODL для выражения класса. За строкой 1 следуют описания трех атрибутов, которые имеют объекты класса Изделие. Первый из них на строке 2 называется назв_изделия, его типом является string – строка символов. Предполагается, что значением атрибута назв_изделия в любом объекте Изделие будет название изделия (пальто, платье и т.д). Следующий атрибут (размер), описанный в строке 3, имеет тип целых чисел, и представляет размер изделия по установленной шкале. На строке 4 описан атрибут тип_материала, показывающий, из чего изготовлено (или изготавливается) изделие. Его тип – перечень сименем Материал. Значения атрибута перечня выбираются из списка доступных литералов, в данном примере – ткань, мех, кожа.
Определенный таким образом объект Изделие можно считать записью, или кортежем, состоящим из четырех компонентов, по одному для каждого атрибута. Например:
("Пальто", 50, кожа) является объектом Изделие.
Пример 4.2.В примере 4.1 атрибуты имеют атомарные типы. Могут быть атрибуты, типами которых являются структуры, множества или множества структур. Ниже приводится пример с неатомарным типом.
Определим класс Мастер:
1) InterfaceМастер {
2) attribute string фамилия;
3) attribute stringимя;
4) attribute stringотчество;
5) attribute Struct Адреса
{string город, integerиндекс, string улица,
stringдом, integerквартира} адрес;
} ;
В строках 1,2,3 определяются атрибуты фамилия, имя, отчество мастера, являющиеся строками. Строка 5 определяет атрибут адрес, имеющий тип структуры записи. Имя этой структуры Адреса, данный тип состоит из пяти полей: город, индекс, улица, дом (номер дома может содержать дроби и буквы, поэтому выбран тип string), квартира. В общем случае в ODL можно определить типы структуры записи с помощью ключевого слова Struct и фигурных скобок, выделяющих список имен полей и их типы.
4.1.4. Связи в ODL
Атрибуты объекта играют большую роль, однако иногда важнее знать то, как они связаны с объектами того же самого или другого класса.
Пример 4.3.Допустим, что к описанию класса Изделие из примера 4.1 добавляется свойство, представляющее множество работающих над ним мастеров. Поскольку сами мастера являются классом, описанным в примере 4.2, информацию о них нельзя сделать атрибутом Изделие, так как типы атрибутов не должны быть классами или строиться из классов. Множество занятых при работе над изделием мастеров, – это связь между классами Изделие и Мастер, которая выражается строкой
relationship Set<Мастер> мастера;
в описании класса Изделие. Эта строка может появиться в примере 4.2 после любой из строк – с 1 по 4. Она означает, что в каждом объекте класса Изделие есть множество ссылок на объекты класса Мастер. Множество ссылок называется мастера. Ключевое слово relationship определяет, что мастера содержит ссылки на другие объекты, а ключевое слово Set, предшествующее <Мастер>, показывает, что мастера ссылается на множество объектов Мастер, а не на единственный объект. В общем случае в ODL тип, являющийся множеством элементов другого типа Т, определяется ключевым словом Set и угловыми скобками, выделяющими тип Т.
Вообще говоря, в физических терминах множество мастера можно было бы представить списком указателей на объекты Мастер; сами объекты Мастер физически не появлялись бы в объекте Изделие. Однако на фазе проектирования БД физическое представление неизвестно и важным аспектом связи является то, что из объекта Изделие легко найти мастеров, работающим над данным изделием.
В примере 4.3 показана связь множества объектов (мастеров) с единственным объектом (изделием). Можно установить и связь единственного объекта с объектом описываемого класса. Предположим, например, что в примере 4.3 был задан тип связи Мастер, а не Set<Мастера >, с помощью строки
relationship Мастер к_мастеру;
Это значит, что с каждым изделием связан только один объект Мастер.
4.1.5. Обратные связи
Любая прямая связь подразумевает наличие обратной связи. Например, можно определять не только мастеров, занятых работой над изделиями, но и изделия, над которыми работал данный мастер. Для получения такой информации в объектах Мастер можно добавить строку
relationship Set<Изделия> от_мастера;
к описанию класса Мастер из примера 4.2. Однако в такой строке и сходном описании Изделие не учитывается очень важный аспект связи между изделиями и мастерами, а именно: если мастер S находится в множестве мастера для изделия M, то M находится в множестве от_мастера для мастера S. Это соотношение связей между множествами мастера и от_мастера выражается тем, что вописании каждой связи указывается ключевое слово inverse и имя другой связи. Если одна из связей находится в другом классе, как это обычно и бывает, ссылка на нее делается с помощью имени этого класса, за которым следуют двойное двоеточие (::) и имя связи.
Пример 4.4.Чтобы определить связь от_мастера класса Мастер как обращение связи мастера в классе Изделие, изменим описание класса Мастер следующим образом:
1) interface Мастер {
2) attribute string фамилия;
3) attribute stringимя;
4) attribute stringотчество;
5) attribute Struct Адреса {string город, integerиндекс, string улица, stringдом, integerквартира} адрес;
6) relationship Set<Изделие> от_мастера
inverseИзделие::мастера;};
В строке 6выражено не только описание связи от_мастера, но и то, что данная связь имеет инверсию – Изделие::мастера. Поскольку связь мастера определена в другом классе, ее имени предшествуют двойное двоеточие и имя этого класса (Изделие). Такая нотацияшироко применяется при ссылках на свойства различных классов.
В примере 4.4 две обратные связи, каждая из которых соединяет объект (изделие или мастера) с множеством объектов. Как упоминалось ранее, есть связи и другого типа, соединяющие объект с единственным объектом другого класса. Понятие обращения связи при этом не изменяется. Общее правило: если связь R для класса С соединяет с объектом х класса С множество объектов y1, y2, ..., уn , то обратная к ней связь соединяет с каждым у объект х (возможно, наряду с другими объектами).
Можно представить связь R класса С с классом D в виде списка пар (или кортежей) отношения. Каждая пара состоит из объекта х из класса С и связанного с ним объекта у из класса D:
C | D |
x1 | y1 |
x2 | y2 |
… | … |
Если R имеет тип Set<D>, то существует несколько пар с одним и тем же С-значением. Если R имеет тип D, существует только одна пара с заданным С-значением. Тогда обращение R есть множество пар с обращенными компонентами:
C | D |
y1 | x1 |
y2 | x2 |
… | … |
Заметим, что это правило действует, даже если С и D являются одним и тем же классом. Существуют связи класса с самим собой, например связь "быть подчиненным" класса "сотрудники" с самим собой.
4.1.6. Множественность связей
Необходимо учитывать, что данный объект связан с единственным объектом или он может быть связан с множеством других объектов. В ODL эти возможности определяются тем, применяется или нет в описании связи оператор множества типа Set. При наличии обратимой пары связей существует четыре возможности: связь может иметь тип "один-к-одному", "один-ко-многим", или "многие-ко-многим".
Рассмотренная связь между мастерами и изделиями относится к типу "многие-ко-многим" и не является уникальной ни в одном направлении: бывает над изделием работают несколько мастеров и один мастер занят со множеством изделий. Следующий пример является развитием предыдущих примеров. В нем вводится класс Цех, представляющий пошивочные цеха, работающие с различными изделиями.
Пример 4.5. Ниже приводится описание трех классов: Изделие, Мастер и Цех. Первые два из них уже были введены в примерах 4.1 и 4.2. Объекты цехов имеют атрибуты название и адрес, появляющиеся в строках 14 и 15. Заметим, что здесь типом адресов является строка, а не структура, использованная для атрибута адрес класса Мастер. В различных классах можно использовать атрибут с одним и тем же именем, но с разными типами.
1) interface Изделие {
2) attribute string назв_изделия;
3) attribute integer размер;
4)attribute enum Материал{ткань, мех, кожа} тип_материала;
5)relationship Set<Мастер> мастера
inverse Мастер::от_мастера;
6)relationshipЦех выполняется_в
inverseЦех::обеспечивает;
};
7) interface Мастер {
8) attribute string фамилия;
9) attribute stringимя;
10) attribute stringотчество;
11) attribute Struct Адреса {string город, integerиндекс, string улица, stringдом, integerквартира} адрес;
12) relationship Set<Изделие> от_мастера
inverseИзделие::мастера;
};
13) interfaceЦех{
14) attribute stringназвание;
15) attribute stringадрес;
16) relationship Set<Изделие> обеспечивает
inverseИзделие::выполняется_в;
};
В строке 6 показана связь выполняется_в между изделиями и цехами. Поскольку ее типом является Цех, а не Set <Цех >, каждое изделие изготавливает только один цех. Обращение данной связи показано в строке 16 – это связь обеспечивает между цехами и изделиями. Ее типом является Set<Изделие>, поэтому каждый цех обеспечивает множество изделий – возможно, ни одно, только одно или большее число изделий.
Требования уникальности связи и ее обращения называются множественностью связей. Наиболее распространенные варианты:
1. Связь типа "многие-ко-многим" класса С с классом D – это связь, в которой с каждым объектом класса С ассоциируется множество объектов класса D, а в ее обращении с каждым объектом класса D ассоциируется множество объектов класса С. В описании, приведенном в примере 4.5, мастера – это связь типа "многие-ко-многим" между классом Изделие и классом Мастер; такой же является связь от_мастера между классами Мастер и Изделие.
В любом направлении связи допускается пустое множество.
2. Связь типа "многие-к-одному" класса С с классом D – это связь, в которой для каждого объекта класса С существует уникальный объект класса D, но в ее обращении с каждым объектом класса D связаны многие С. В примере 4.5 выполняется_в – это связь типа "многие-к-одному" класса Изделие с классом Цех. Обратная ей связь – это связь типа "'один-ко-многим" класса D с классом С. В том же примере обеспечивает – связь типа "один-ко-многим" класса Цех с классом Изделие.
3. Связь типа "один-к-одному" класса С с классом D – это связь, в которой для каждого объекта класса С существует уникальный объект класса D.
В обратной связи каждый объект класса D связан с уникальным объектом класса С. В описание из примера 4.5 можно добавить класс Начальник, представляющий начальников цехов. Предполагается, что каждый цех имеет единственного начальника и ни один человек не может быть начальником более чем одного цеха. Значит, связь между цехами и их начальниками имеет тип "один-к-одному" в обоих направлениях.
При описании связей следует иметь в виду, что связь типа "многие-к-одному" – это частный случай связи типа "многие-ко-многим", а связь типа "один-к-одному" – частный случай связи типа "многие-к-одному". Любое полезное свойство связей типа "многие-ко-многим" применимо к связям типа "многие-к-одному", а полезные свойства последних верны и для связей типа "один-к-одному". Например, структура данных для представления связей типа "многие-к-одному" подходит для связей типа "один-к-одному", но может быть непригодна для связи типа "многие-ко-многим".
Используя термины типа "уникальный" или "один" при определении связей типа "многие-к-одному" или "один-к-одному" необходимо учитывать некоторую неопределенность. Важно считать, что "уникальный" или "один" элемент реально существует. Например, для каждого изделия реально существует пошивочный цех, а цех возглавляет реальный начальник. Однако есть все основания считать, что в реальности уникального объекта не существует. Например, цех может временно работать без начальника или же мы можем не знать какому цеху относится конкретное изделие.
Таким образом, обычно допускается, что предполагаемое значение связанного объекта может отсутствовать. Значение "null" часто допускается в БД там, где предполагается наличие истинного значения. Например, в терминологии традиционного программирования указатель "null" может стоять там, где предполагается указатель на единственный объект.
4.1.7. Типы в ODL
Средства ODL предоставляют проектировщику систему типов, подобную системам типов языка С или других популярных языков программирования. Система типов строится из базовых типов, которые определены сами по себе, с помощью конкретных рекурсивных правил (сложные типы строятся из более простых). Базовые типы ODL:
1. Атомарные типы: целое число с плавающей точкой, символ, строка символов, булево выражение и перечисление. Последний тип – это список имен, объявленных синонимами целых чисел. Перечисление содержится в строке 5 примера 4.4, где имена ткань, мех, кожа в результате были определены как синонимы чисел 0, 1, 3.
2. Типы интерфейса, например Изделие и Мастер, являются реальными структурами с компонентами для каждого атрибута и каждой связи данного интерфейса. Эти имена представляют сложные типы, определяемые с помощью перечисленных ниже типов, но их можно считать базовыми.
Базовые типы комбинируются в структурные типы с помощью следующих конструкторов типов:
1. Множество. Если T -любой тип, то Set<T> обозначает тип, значениями которого являются все конечные множества элементов типа Т.
2. Мультимножество. Если Т – любой тип, то Bag<T > обозначает тип, значениями которого являются все мультимножества элементов типа Т. Мультимножество допускает многократное повторение одного и того же элемента. Например, {1, 2, 1} – это мультимножество, а не множество, так как 1 повторяется в нем дважды.
3. Список. Если Т– любой тип, то List<T> обозначает тип, значениями которого являются конечные списки, состоящие из нуля или более элементов типа Т. В специальном случае тип string является сокращением типа List<char>.
4. Массив. Если Т– любой тип, то Аггау<Т> обозначает тип, элементами которого является массив из i элементов типа Т. Например, Array<char,10> обозначает символьную строку длиной 10.
5. Структуры. Если Т1,T2, ..., Тn являются типами, a F1, F2, ..., Fn именами полей, то
Struct N {Т1F1,T2F2…,TnFn}
обозначает тип с именем N, элементами которого служат структуры, содержащие п полей; i-е поле имеет имя Fi и тип Тi. Например, строка 10 в примере 4.4 показывает тип структуры с именем Адрес с пятью полями.
Для того чтобы различать множества, мультимножества и списки следует помнить, что элементы множества не упорядочены и каждый из них входит в данное множество только один раз. Мультимножество допускает более одного вхождения любого элемента, но элементы и их вхождения не упорядочены. В списке может быть несколько вхождений одного и того же элемента, но все вхождения в нем упорядочены. Значит, {1, 3, 1} и {3, 1, 1} – это одно и то же мультимножество, но {1, 3, 1} и {3, 1, 1} – это разные списки.
Первые четыре типа – множество, мультимножество, список и массив – называются типами множеств. Существуют правила, определяющие, какие типы можно ассоциировать с атрибутами, а какие со связями.
Построение типа атрибута начинается с атомарного типа или со структуры, полями которой являются атомарные типы. Затем по выбору можно применить тип множества к исходному атомарному типу структуры.
Тип связи – это или тип интерфейса, или тип набора, примененный к типу интерфейса.
Важно помнить, что типы интерфейса могут не появляться в типе атрибута, а атомарные типы – в типе связи. В этом отличие атрибутов и связей друг от друга. Разница между ними еще и в том, как строятся для них сложные типы: и атрибут, и связь допускают произвольный тип множества в качестве последнего оператора, но тип структуры допустим только в атрибутах.
Пример 4.6.Возможные типы атрибутов:
1) integer.
2) Struct N {string fieldl, integer field2}.
3) List<real>.
4) Array<Struct N {string fieldl, integer field2}>.
Здесь 1 – атомарный тип, 2 – структура атомарных типов, 3 – множество атомарного типа, а 4 – множество структур, построенных из атомарных типов.
Допустим, что доступными базовыми типами являются имена интерфейсов Изделие и Мастер. Тогда можно построить типы связи Изделие или Bag<Мастер>. Однако следующие типы связей недопустимы:
1. Struct N {Изделие fieldl, Мастер field2}. Типы связей не могут включать в себя структуры.
2. Set<integer>. Типы связей не могут содержать атомарные типы.
3. Set<Array<Мастер>. Типы связей не могут содержать два применения типов множества (их не могут содержать и типы атрибутов).
4.1.8. Проектирование с использованием ODL
В данном разделе рассматриваются некоторые полезные принципы проектирования с использованием объектно-ориенти-рованного подхода.
Правильность
Самое важное: проект должен быть адекватным конкретной предметной области, правильно отображать реальный мир. Классы или множества сущностей и их атрибуты, должны отражать реальные объекты. Нельзя приписывать мастеру-портному атрибут "число цилиндров", хотя это имеет смысл для класса автомобилей. Любые установленные связи должны соотноситься с нашими знаниями о моделируемой части реального мира.
Пример 4.7.Если определяется связь мастер_для между Мастер и Изделие, она должна быть типа "многие-ко-многим", так как наблюдения за реальным миром показывают, что мастера могут быть заняты работой над многими изделиями, и изделия могут (не обязательно, но могут) выполняться несколькими мастерами. Неверно определять эту связь как " связь типа "один-к-одному".
Устранение избыточности
Необходимо следить за тем, чтобы каждый факт упоминался не более одного раза. Например, мы использовали связь обеспечиваетмежду изделиями и цехами. Можно было бы еще ввести атрибут название_цеха или множество сущностей Изделия, в чем нет ничего незаконного. Однако это опасно по многим причинам.
1. Необосновано увеличивается необходимый объем памяти, одно описание факта займет всегда меньше места, чем два описания.
2. Могут возникать аномалии удаления и изменения данных. Например, данные о каком-либо факте могут быть изменены в одном месте, а в другом по недочету оставлены прежними, т. е. повышается вероятность наличия противоречий в базе данных.
С первого взгляда может показаться, что использование связи и ее обращения в ODL – это пример излишеств в модели. Однако не следует полагать, что связь и ее обращение будут представлены двумя различными структурами данных, например указателями в различных направлениях. Вспомните, что определение связи и ее обращения лишь отражают тот факт, что связи в принципе можно придать любое направление.
Если же связь действительно реализуется двумя отдельными структурами данных, возникает риск, связанный с избыточностью. Поскольку предполагается, что базовые указатели постоянно используются при изменении данных, при реализации СУБД, основанных на ODL, нужно внимательно относиться к способам изменений БД. Но эта проблема относится к уровню системы, причем предполагается, что разработчики системы успешно (в конечном счете) с ней справятся. На уровне реализации с избыточностью связан меньший риск, и существование указателей в обоих направлениях может привести к существенному повышению скорости, с которой связи придается то или иное направление.
И еще один важный момент. Не стоит вводить в проект больше элементов, чем это необходимо.
4.1.9. Подклассы
Наследование является одним из основополагающих принципов ООП. Довольно часто класс содержит объекты с особыми свойствами, не связанными со всеми членами этого класса. В данном случае рекомендуется разделить класс на подклассы, каждый из которых будет иметь собственные специальные атрибуты и/или связи в дополнение к тем, что присущи классу как единому целому. Сначала рассмотрим простой способ описания подклассов в ODL, а затем (в следующей главе) покажем, как иерархии класс-подкласс представляются в E/R-модели с помощью специальных связей под названием "isa" ("А есть В" выражает связь "isa" подкласса А с подклассом В).
В рассматриваемом в качестве примера БД ателье могут заказываться платья, костюмы, шубы и множество других типов изделий. Для каждого из этих типов можно определить подкласс класса Изделие, введенного в примере 4.1. По определению класс С является подклассом другого класса D если в описании за именем С следуют двоеточие и имя класса D.
Пример 4.8.Дляиллюстрации будем различать труд портного и скорняка. Меховое_изделие – это подкласс класса Изделие, следовательно, Изделие – это суперкласс класса Меховое_изделие. Выразим это простым ODL-описанием:
1) interfaceМеховое_изделие: Изделие {
2) relationship Set<Мастер> скорняжный_пошив;
};
Строка (1) показывает, что Меховое_изделие – подкласс класса Изделие. Строка (2) означает, что все объекты класса Меховое_изделие имеют связь скорняжный_пошив с мастерами, выполняющими скорняжную работу. В описании не указано имя обращения этой связи, хотя технически это следовало бы сделать. Заметим, что связь скорняжный_пошив имеет смысл не для всех изделий, а только для меховых изделий, поэтому не вводится для класса Изделие.
Подкласс наследуетвсе свойства своего суперкласса (называемого также классом, из которого выводитсяподкласс). Другими словами, любые атрибут и связь суперкласса автоматически являются атрибутом и связью его подкласса. В примере 4.8 каждый объект класса имеет все атрибуты, наследованные от Изделие (вспомните пример 4.4), и в дополнение к собственной связи скорняжный_пошив наследует от Изделие связи мастера и выполняется_в.
4.1.10. Множественное наследование в ODL
У класса может быть несколько подклассов, каждый из которых наследует свойства своего суперкласса, как было показано в предыдущем разделе. Более того, подклассы сами могут иметь подклассы, образуя иерархию классов, в которой каждый класс наследует свойства своих предшественников. Некоторые классы могут наследовать свойства из нескольких различных. Следующий пример иллюстрирует потенциальные возможности и проблемы, связанные с такой ситуацией.