Объектно-ориентированная СУБД (прототип)
самым дешевый (Jasmine стоит порядка $15000), но эффективный инструмент,
способный работать даже в самых непритязательных условиях, которые так
часто встречаются сейчас в России. Разработка не ограничивается расширением
ДССП и способна работать в качестве сервера ООБД на файл-сервере ЛВС.
1.5 Анализ полученного результата
В результате проделанной работы изучена литература по организации
реляционных баз данных, подходы к организации объектно-ориентированных баз
данных. Были отобраны математические модели, на основании которых была
определена архитектура базы данных и принципы ее функционирования.
Программно реализованы подсистемы управления виртуальной памятью и
кэширования объектов. Сама работа носит исследовательский характер, являясь
шагом от чистой теории к идеям реализации ООБД. Обширность тематики не
позволила проработать детально все вопросы, касающиеся организации ООБД. В
частности, очень мало места уделено средствам повышения производительности
поиска в БД (индексирование). Тем не менее, некоторые найденные решений, на
мой взгляд, являются весьма перспективными. Это касается организации
виртуальной памяти, позволяющей организовать произвольную степень
вложенности данных, и механизма кэширования, которые подробно
рассматриваются в работе.
В виде программного кода реализовано:
. Создание, открытие ООБД
. Менеджер виртуальной памяти
. Система управления каналами
. Система управления кэшированием объектов
. Создание основных объектов
. Клонирование объектов
. Переопределение поведений и действий
. Изменение данных в объектах
. Журнализация изменений в объектах
. Выполнение действий (knowhow)
2. Уточнение методов решения задачи
2.1 Наследование
Наследование является мощным средством моделирования (поскольку кратко
и точно описывает мир) и помогает программисту разрабатывать новые версии
классов и методов, не опасаясь повредить работающую систему. Наследование
способствует повторному использованию кода, потому что каждая программа
находится на том уровне, на котором ее может использовать наибольшее число
объектов.
Совокупности свойств объекта в объектно-ориентированной базе данных
уделяется большее внимание, чем во многих объектно-ориентированных языках
программирования, поскольку они являются также целью запросов.
Объект=состояние+поведение. Чаще всего существует только одна иерархия
наследования. Этот подход перешел и в C++. Однако, возможно разделение
иерархий наследования данных и наследования поведений. Не всегда желательно
иметь точно такую же иерархию наследования поведения, как и иерархию
наследования свойств. Разделение этих двух иерархий повышает возможности
переиспользования (reuse) поведений.
Значение переиспользования поведений
Предположим, мы имеем класс Студент и хотим создать класс Аспирант.
Чтобы стать аспирантом, человек должен сначала получить высшее образование
как студент. В общем случае экземпляры этих классов различны. Мы не можем
наследовать Аспирант от Студент, т.к. аспирант не является студентом. В
противном случае, мы имели бы право рассматривать аспиранта как экземпляр
класса Аспирант и, с тем же правом, как экземпляр класса студент. Тем не
менее, оба класса обладают общими атрибутами, такими как: имя, адрес,
номер_личной_карточки, а также большинством общих поведений. Это
обстоятельство побуждает создать класс Аспирант, унаследовав свойства и
поведения Студента. Однако, хотя экземпляры класса Аспирант будут
подмножеством всех экземпляров класса Студент (т.к. все аспиранты были
студентами, но не все студенты стали аспирантами), это представление будет
некорректно с точки зрения моделирования ситуации в реальном мире.
На рисунке представлено дерево наследования:
[pic]
Рис. 2: Диаграмма наследования
Свойства классов Студент и Аспирант наследуются от класса Учащийся.
Поведение класса Аспирант наследуется от Студент. Обычно подкласс
наследует все атрибуты и методы из суперклассов. В приложении к
наследованию поведений это означает, что класс-ученик (demandclass) состоит
в отношении Переиспользовать-от (Reuse-Of) с другим классом, называемым
классом-учителем (supplyclass), и класс-ученик должен наследовать все
поведения от класса-учителя.
Эталоны наследования: классы или прототипы?
В системе отсутствуют классы и типы. Роль класса может брать на себя
любой объект, называемый объектом-образцом. Такой вид наследования
называется наследованием на основе прототипов.
Как правило, системы с наследованием на основе прототипов
концептуально более просты по сравнению с системами на основе классов.
Порождение экземпляра достигается копированием объекта-образца. Копия
получает от системы уникальный идентификатор, отличный от идентификатора
любого другого объекта в системе.
Независимо от модели наследования (классы или прототипы) существует
две различные стратегии реализации механизма наследования: делегирование и
конкатенация.
Способ наследования: делегирование или конкатенация?
Делегирование представляет собой такую форму наследования, в которой
объединение интерфейсов реализовано посредством разделения родительских
интерфейсов, т.е. с использованием ссылок. Конкатенация достигает
аналогичного эффекта посредством копирования родительских интерфейсов в
интерфейс порождаемого класса или объекта, – как результат, полученный
интерфейс является непрерывным. В любом случае дочерний объект способен
отвечать как на сообщения, определенные в родительских интерфейсах, так и
на сообщения, добавленные к интерфейсу объекта. При делегировании те
сообщения, которые не могут быть обработаны объектом, должны быть
направлены родителям. При конкатенации каждый объект является
самодостаточным, и необходимость перенаправления сообщений отсутствует.
Введение идентификаторов полей позволяет распространить подходы
делегирования и конкатенации и на агрегатные объекты.
И конкатенация, и делегирование имеют свои достоинства и недостатки.
Делегирование обеспечивает возможность гибкого распространения изменений:
любое изменение свойств родителя автоматически отражается на потомках.
Подход, использующий конкатенацию, допускает изменение свойств родителей и
потомков независимо друг от друга, что также может быть полезно во многих
ситуациях. Делегирование обычно требует меньших затрат по памяти, в то
время как конкатенация является более эффективной по времени. Simula и C++
являются примерами языков, которые реализуют наследование на основе классов
с использованием делегирования. В Smalltalk реализовано наследование на
основе прототипов с использованием делегирования.
Обоснование избранного механизма наследования
Было решено использовать в дипломной работе механизм наследования на
основе прототипов с использованием конкатенации, как для состояний, так и
для поведений, поскольку для СУБД критично именно время выполнения
операций. Разделение наследований состояния и поведения позволяет уменьшить
объем хранимой в каждом объекте информации. В объект помещается ссылка на
объект, хранящий его интерфейс (т.е. поведение). Таким образом, интерфейсы
многих объектов с одинаковым поведением могут быть сосредоточены в одном
месте. Наследование на основе прототипов позволяет управлять конфигурацией
объектов-образцов и обеспечивает единство представления данных. Т.е.
результатом запроса к базе данных может быть список используемых методов,
их аргументы и другая информация, которая в системе с наследованием на
основе классов скрыта в классах. Создание экземпляра через копирование
снимает необходимость введения конструктора по умолчанию, поскольку
содержимое копируемого объекта и задает начальные значения.
Система поддерживает множественное наследование. Необходимость
множественного наследования остается предметом горячих споров. Практика
говорит о том, что «множественное наследование играет роль парашюта: в нем
нет постоянной необходимости, но если он вдруг понадобился, то большое
счастье иметь его под рукой» [8].
Определение родства
Остается важный вопрос: как определить, является ли объект потомком
другого объекта? Разделение наследований состояния и поведения приводит к
тому, что слово «потомок объекта» обретает двойственное значение. С одной
стороны, это потомок по данным, с другой стороны, это потомок по поведению.
На самом деле, в чистой объектно-ориентированной системе данные
объектов надежно защищены от вмешательства пользователя через механизм
инкапсуляции. Доступ к данным производится через методы. Таким образом,
родство объектов следует определять исключительно через их интерфейсы. В
системе на основе классов обычно строится дерево наследования. В системе
на основе прототипов с конкатенацией определение родства достигается за
счет операций пересечения интерфейсов. Поведение объекта составляют методы,
хранящиеся в объекте-множестве, а значит для определения родства необходимо
выполнить операцию пересечения множеств. Если получившийся в результате
пересечения интерфейс совпадает с интерфейсом одного из двух сравниваемых
объектов, то другой объект – его потомок. Фактически, это алгоритм
определения общего предка двух объектов. Использование множеств для
хранения интерфейсов позволяет взглянуть на операцию наследования
конкатенацией как на операцию слияния множеств.
2.2 Инкапсуляция
Идея инкапсуляции в языках программирования происходит от абстрактных
типов данных. С этой точки зрения объект делится на интерфейсную часть и
реализационную часть. Интерфейсная часть является спецификацией набора
допустимых над объектом операций. Только эта часть объекта видима.
Реализационная часть состоит из части данных (состояние объекта) и
процедурной части (реализация операций).
Интерпретация этого принципа для баз данных состоит в том, что объект
инкапсулирует и программу и данные.
Рассмотрим, например, объект Служащий. В реляционной системе служащий
представляется кортежем. Запрос к нему осуществляется с помощью
реляционного языка, а прикладной программист пишет программы для изменения
этой записи, например повышение зарплаты служащего или прием на работу.
Такие программы обычно пишутся либо на императивном языке программирования
с включением в него операторов языка манипулирования данными или на языке
четвертого поколения и хранятся в обычной файловой системе, а не в базе
данных. Таким образом, при таком подходе имеются кардинальные различия
между программой и данными, а также между языком запросов (для
незапланированных запросов) и языком программирования (для прикладных
программ).
В объектно-ориентированной системе служащий определяется как объект,
который состоит из части данных (очень даже вероятно, что эта часть
практически совпадает с записью, определенной для реляционной системы) и
части операций (эта часть состоит из операций повышения зарплаты и приема
на работу и других операций для доступа к данным сотрудника). При хранении
набора сотрудников, как данные, так и операции хранятся в базе данных.
Таким образом, имеется единая модель данных и операций, и информация может
быть скрыта. Никакие иные операции, кроме указанных в интерфейсе, не
выполняются. Это ограничение справедливо как для операций изменения, так и
для операций выборки.
Инкапсуляция обеспечивает что-то вроде “логической независимости
данных”: мы можем изменить реализацию типа, не меняя каких-либо программ,
использующих этот тип. Таким образом, прикладные программы защищены от
реализационных изменений на нижних слоях системы.
Здесь уместно вспомнить о “проблеме 2000 года”, возникшей из-за того,
что в СУБД отводилось всего два разряда на год даты. Чтобы исправить
возникающую ошибку, нужно пересмотреть заново весь код приложения! В ООБД
для решения аналогичной проблемы требуется исправление небольшого
количества методов, работающих с данными даты.
2.3 Идентификатор объекта
Назначение идентификатора
Объекты в БД обладают индивидуальностью. Даже при изменении структуры
и поведения объекта, его индивидуальность сохраняется. Два объекта в
системе отличаются своими идентификаторами. Идентификатор является
характеристикой индивидуальности. Понятие индивидуальности ново для
реляционных баз данных. В чисто реляционной БД все кортежи в пределах одной
таблицы отличаются между собой. Характеристика различия – первичный ключ.
Многие современные реляционные базы данных допускают существование в
пределах одной таблицы одинаковых кортежей. И потребность в этом есть,
иначе не было бы квалификатора DISTINCT в операторе SQL SELECT.
Идентификатор объекта в БД позволяет различить между собой два
одинаковых по значению объекта. Фактически, он играет роль дескриптора
адреса объекта. Таким образом, пользователь работает с объектом не через
его адрес, а через его идентификатор.
Строение идентификатора
В современных ООБД для ускорения доступа к объектам идентификаторы
наделяются составной структурой.
Имеются два основных подхода для идентификации объектов:
. Составной адрес (Structured address)
. Заменитель (Surrogate)
Составной адрес состоит из физической части (сегмента и номера
страницы) и логической части (внутристраничный индекс), которые являются
масками фиксированной длины и, соединяясь, дают идентификатор. Составные
адреса более популярны в современных ООБД как более эффективные: за один
дисковый доступ можно получить адрес объекта. Использование составного
адреса как идентификаторов приводит к зависимости от организации
физического хранения. Это приводит к трудностям при перемещении данных для
хранения на другое устройство.
Заменитель – чисто логический идентификатор, генерируемый по
некоторому алгоритму, который гарантирует уникальность. В заменителях,
индекс (также называется директорией объекта), часто используется для
отображения идентификаторов в расположение объектов. Эффективность операций
с базой данных во многом определяется скоростью доступа к одиночному
объекту. Часто объекты связаны между собой и доступ к одному объекту
происходит через доступ к другому. Например, через объект-список происходит
доступ к его элементам. Во многих случаях создание объекта (например,
глубоким копированием) приводит к каскадному созданию других объектов,
составляющих его содержимое. Использование кластеризации помогает
организации быстрого доступа к группе связанных объектов. Кроме того,
размещение объектов в одной области дискового пространства также
увеличивает быстродействие.
В работе [16] описан подход к построению идентификаторов-заменителей.
Идентификатор состоит из двух частей: кода кластера и номера в
последовательности. Такой подход основывается на следующих трех принципах:
1) Идентификатор объекта должен содержать информацию о кластере,
который группирует совместно используемые объекты
2) Должны быть допустимы произвольные размеры кластеров
3) Идентификаторы объектов должны подчиняться достаточно однообразному
представлению, чтобы они могли выступать в качестве псевдоключей
динамического хеширования.
Есть три признака, по которым СУБД могут принимать решение о месте
размещения объектов:
1) Правила, заданные в схеме БД
2) Указание пользователя
3) Статистика доступа
В дипломной работе, несмотря на заманчивость идеи кластеризации,
принят тривиальный подход: идентификатор нового объекта – это значение
максимального идентификатора, использующийся в системе, плюс один. Объекты
также хранятся не в виде кластеров и не вкладываются друг в друга. Хотя
система управления памятью позволяет организовать и такой способ хранения.
Идентичность и эквивалентность
В ООБД при сравнении двух объектов между собой различают идентичность
и эквивалентность объектов.
Определение идентичности
Два объекта являются идентичными, если их идентификаторы совпадают.
Поскольку в системе не может быть двух объектов с одинаковыми
идентификаторами, это означает, что это один и тот же объект, на который
ссылаются с двух разных мест. Идентичность обозначается так: o1 ( o2.
Определение N-эквивалентности
Пусть 0-эквивалентность (обозначается (0) то же самое, что проверка
идентичности (. Тогда для любых двух объектов o1, o2(O, o1 и o2 n-
эквивалентны (обозначается o1 (n o2) для n > 0, если:
Существует атомарный объект c, такой, что значение(o1) = значение(o2)
и их поведения идентичны;
Существует объект-агрегат c, такой, что FID каждого поля с
присутствует в o1 и o2, а также верно обратное: FID каждого поля o1 (o2)
присутствует в c,
значение(o1)=[A1 : x1, …, Am : xm] и значение(o2)=[A1 : y1, …, Am : ym], и
при этом
xi (n-1 yi для 1( i ( n; или
Существует объект-условие c, такой, что значение(o1) =
и значение(o2) = и xi (n-1 yi для 1( i ( 3; или
Существует объект-множество c, такой, что значение(o1) = {x1, …, xl}
Страницы: 1, 2, 3, 4, 5
|