Привет Всем!
Тех кто интересуется этой темой, я хочу попросить о помощи в оценке удобства архитектуры моей ООСУБД. Что можно в ней изменить, чтобы ее интерфейсом было бы удобнее пользоваться из среды C# ?
Рассмотрим архитектуру сетевой объектно ориентированной базы знаний Cerebrum.
СУCООБЗ Cerebrum это многоуровневая система состоящая из нескольких модулей. Модули составляют иерархию, так что более высокий уровень использует в своей работе модули более низкого уровня. Это позволяет определить и использовать несколько модулей Cerebrum оптимально соответсвующих решению поставленной задачи.
Cerebrum.Runtime.dll — это ядро системы. В нем расположены самые низкоуровневые операции. Его можно рассматривать как усовершенствованный менеджер памяти и файловой системы. Например, в нем находится сборщик мусора, управляющий persistent объектами. На основе этого компонента можно реализовать различные архитектуры баз данных и знаний, однако, так как функции, реализованные в нем, достаточно низкого уровня и не определяют архитектуру приложения, использовать этот модуль независимо от остальных будет неудобно — потребуется продублировать код уже доступный в других модулях. Поэтому его удобно использовать в комплекте с несколькими вышестоящими модулями.
Cerebrum.Integrator.dll — это реализация БД конфигурации. Ядро требует метаинформацию о классах .NET управляемых системой. В нем находятся реализации дескрипторов такой метаинформации, например AttributeDescriptor, TableDescriptor, TypeDescriptor и.т.п. Этот модуль не накладывает ограничений на остальную архитектуру программы. Если необходимо использовать Cerebrum в web сайте через ASP.NET то следует ограничится использованием этого модуля, так как архитектура Windows.Forms приложения отличается от Web.
Cerebrum.Windows.Forms — это ядро приложения для Windows.Forms. Если предполагается использовать Cerebrum в своем приложении, то потребуется включить в проект эту и 2 ранее перечисленные DLL .
Cerebrum.DesktopClient.exe — это законченное приложение для просмотра и изменения БД конфигурации. Так же оно разработано с учетом поддержки add-ins. Существует возможность разработать адд-инс и включить его как составную часть Cerebrum.DesktopClient.exe. Выбор между включением Cerebrum в независимое приложение и включением приложения в Cerebrum зависит от целей разработки.
Важной особенностью СООБЗ Cerebrum является отличие в адресации объектов по сравнению с манифестом объектных баз данных ODMG. В Cerebrum каждый объект, так же ккак и в ODMG адресуется с использованием мягкого указателя или что тоже самое, ID объекта Cerebrum.Runtime.NativeHandle . Получение указателей на экземпляры объектов внешние по отношению к некторому текущему объекту производится в пределах контекста текущего объекта. Объект может адресовать только те объекты, с которыми он установил связь. Каждый связанный с текущим объект имеет идентификатор. Каждый уникальный идентификатор определяет в пределах текущего объекта экземпляр связанного с ним объекта. В пределах текущего объекта каждый идентификатор может адресовать только один экземпляр. Однако важным отличием от ODMG зедсь является возможность иметь в пределах некоторого объекта несколько различных NativeHandle адресующих один и тот же экземпляр. Тоесть в пределах некоторого заданного объекта несколько разных идентификаторов могут ссылаться на один и тот же экземпляр объекта. В отличии от ODMG, где каждый объект имеет только один уникальный идентификатор. Если рассмотреть не один экземпляр, а всю базу, то по аналогии с явлениями естественного языка синонимии и омонимии в СООБЗ Cerebrum возникаеют являения синонимии и омонимии идентификаторов объектов. Так в различных контекстах определяемых различными экземплярами объектов один и тот же идентификатор объекта NativeHandle может адресовать как разные экземпляры, так и один и тот же экземпляр. Это явление можно назвать омонимией объектных идентификаторов. Так же как и в естественном языке при омонимии один и тот же идентификатор в разных контекстах одной и той же базы данных может адресовать как различные так и одинаковые экземпляры объектов. Так же как в одном и том же контексте, так и в разных контекстах различные идентификаторы могут ссылаться на один и тот же экземпляр объекта. В этом случае возникает явление синонимии объектных идентификаторов, когда один экземпляр может иметь в пределах базы множество различных идентификаторов — синонимов. Эту возможность удобно использовать для построения семантических и иерархических семантических сетей.
С точки зрения разработчика Cerebrum представляет собой совокупность объектов различного назначения. В одном процессе возможно существование нескольких открытых баз данных. Каждая база данных доступна разработчику в виде объекта реализующего интерфейс IWorkspace. Экземпляр, реализующий этот интерфейс можно считать корнем базы данных.
public interface INativeDomain : System.IDisposable
{
IActivator Activator { get; }
IContainerEx GetSector();
}
public interface IWorkspace : INativeDomain, IContainer
{
IActivator Activator { set; }
void BeginTransaction();
void CommitTransaction();
NativeHandle CurrSequence();
NativeHandle NextSequence();
void RollbackTransaction();
void RollbackTransaction(bool all);
}
где
Activator — свойство, позволяющее установить фабрику пользовательских объектов;
GetSector- метод, возвращающий оболочку корневого индекса пользовательских экземпляров;
NextSequence- метод, возвращающий следующий уникальный идентификатор объекта;
CurrSequence- метод, возвращающий последний сгенерированный идентификатор.
Этот объект так же обладает контекстом позволяющим проводить разадресацию идентификаторов в указатели на объекты. Разадресация производится с использованием интерфейса IContainer являющегося базовым для интерфейса IWorkspace. IWorkspace так же является оболочкой к объекту DomainContext представляющему базу данных на уровне Cerebrum.Integrator.
Интефейс IContainer содержит следующие методы:
public interface IContainer : IDisposable
{
IComposite AttachConnector(NativeHandle plasma);
IComposite CreateConnector(NativeHandle plasma, NativeHandle typeID);
void EngageConnector(NativeHandle plasma, IConnector connector);
void RemoveConnector(NativeHandle plasma);
}
где
AttachConnector — метод возвращающий объект-оболочку пользовательского объекта по идентификатору этого объекта;
CreateConnector — метод, создающий экземпляр пользовательского объекта и возвращающий его оболочку;
RemoveConnector — метод, удаляющий экземпляр пользовательского объекта из текущего контейнера. В случае удаления пользовательского объекта из всех контейнеров, объект полностью удаляется из базы данных;
EngageConnector — метод, подключающий существующий экземпляр пользовательского объекта к текущему контейнеру с заданным идентификатором.
При использовании AttachConnector или CreateConnector возвращается оболочка экземпляра IComposite. Интерфейс IComposite наследует у интерфейса IConnector. IConnector имеет следующие свойства:
public interface IConnector : IDisposable
{
object Component { get; set; }
IWorkspace Workspace { get; }
}
где
— свойство, возвращающее экземпляр пользовательского объекта;
— свойство возвращающее корневой интерфейс базы данных.
IComposite имеет следующие свойства:
public interface IComposite : IConnector
{
NativeHandle GroundHandle { get; }
NativeHandle LiquidHandle { get; }
NativeHandle PlasmaHandle { get; }
NativeHandle TypeIdHandle { get; }
IConnector GetPrecedent();
}
где
— свойство, возвращающее логический идентификатор экземпляра;
— свойство, возвращающее идентификатор типа экземпляра в таблице Types.
— свойство возвращающее объект-оболочку родительского объекта;
— свойство, возвращающее идентификатор объекта в хранилище;
— свойство, возвращающее идентификатор объекта в кэш.
Контекст экземпляра определяется объектом оболочкой IConnector Если данный экземпляр имеет возможность устанавливать связи с другими объектами, то объект оболочку IConnector возможно привести к типу IContainer и использовать его для разадресации некоторого идентификатора NativeHandle вместо IWorkspace.
Модель данных СООБЗ Cerebrum представляет собой сеть.
Узел в Cerebrum является агрегатом нескольких объектов. Во первых это объект ядра. Объект ядра определяет роль данного узла в модели данных. Непосредсвенно в Cerebrum.Runtime.dll для использования пользователем доступны 3 различные типа объектов ядра. Это Scalar, Stream и Warden. Scalar объекты служат для создания узлов, хранящих скалярные значения, например System.Int32 или System.String. Такие узлы не могут вступать в связь с другими узлами в качестве родительских объектов. Или что то же самое такие узлы не могут являться источниками связей. Узлы типа Scalar могут выступать только в качестве дочерних объектов. Узлы типа Stream похожи на узлы Scalar, но в место скалярных значений они хранят потоки байт по аналогии с полем BLOB в РСУБД.
Узлы типа Warden могут быть связанны с другими узлами с помощью однонаправленных связей. Каждой связи должен быть назначен идентификатор. Из узла источника связи возможно обнаружить связанный с ним экземпляр. Однако из узла на который указывает связь невозможно определить ни узлы, их которых исходят связи, ни сам факт наличия связи. Можно сказать, что узел источник связи является родительским объектом, а узел приемник связи – дочерним. При этом нельзя для некоторого конкретного объекта определить родительский объект. Таких родительских узлов у каждого экземпляра может быть несколько. Для совместимости с паттерном FLYWEIGHT в узлах в Cerebrum не храняться ссылки на родительские узлы, и также невозможно определить идентификатор текущего объекта из внутреннего контекста этого объекта.
Вторым объектом в агрегате является экземпляр реализующий интерфейс IConnector. Этот экземпляр передается в пользовательский объект при его инициализации. Через свойство IConnector.Workspace пользовательский объект имеет доступ к экземпляру, реализущиму интерфейс IWorkspace.
Третьим объектом в агрегате является экземпляр пользовательского объекта. В Cerebrum допускается делать Persistent пользовательске объекты унаследованные от любого базового объекта. Если родительский объект получил по идентификатору адрес объекта оболочки дочернего объекта, то экземпляр дочернего пользовательского объекта доступен через свойство IConnector.Component.
Для того чтобы получить указатель на экземпляр пользовательского объекта необходимо вызвать метод AttachConnector в контексте родительского объекта, передав в качестве параметра идентификатор экземпляра, адресующий дочерний объект в пределах родительского контекста. В результате вызова данного метода система вернет новый экземпляр объекта оболочки, реализующей интерфейсы IConnector и IComposite. В случае если в качестве объекта ядра был задан Warden объект оболочка реализует так же и интерфейс IContainer
В сети нет четкого понятия иерархии. В БД любой объект может выступать как родительский и как дочерний, мало того, объекты могут быть своими собственными родительскими и дочерними объектами. Так же разрешается иметь циклы когда объект А является родительским у объекта B и объект B является родительским у объекта A. Это приводит к затруднению в определении «начала» БД с которой необходимо начать работу непосредсвенно после запуска системы. Для этого в БД реализован специальный корневой экземпляр объекта — Sector. Sector представляет собой отдельный экземпляр объекта ядра Warden. При необходимости указатель на его оболочку можно получить как IWorkspace.GetSector() однако для удобства и повышения эффективности его интерфейс IContainer совмещен с интерфейсом IWorkspace и доступен через IWorkspace напрямую.
В большинстве случаев удобно, когда дочерними узлами объекта Sector являются большинство экземпляров пользовательских объектов имеющие объекты ядра Warden. Их дочерними объектами являются скалярные значения, имеющие объекты ядра Scalar.В результате объекты ядра образуют трехуровневое дерево. На первом уровне этого дерева находится объект ядра Sector. На втором уровне находятся экземпляры пользовательских объектов, каждый узел имеет дочерние узлы. Экземпляры пользовательских объектов, находящиеся на втором уровне удобно адресовать уникальными в пределах всей базы данных идентификаторами, аналогично преложению ODMG. Для обеспечения этой возможности объект Sector предоставляет sequence для получения уникальных значений идентификаторов объектов как IWorkspace.NextSequence(). На третьем уровне находятся скалярные значения, представляющие собой аттрибуты пользовательских объектов. Дочерние узлы в пределах узла пользовательского экземпляра адресуются с помощью идентификаторов NativeHandle. Если пользовательские объекты имеют уникальные идентификаторы в пределах объекта Sector то их аттрибуты имеют уникальные идентификаторы только в пределах одного экземпляра. Аттрибуты различных пользовательских объектов обладающие одинаковой семантикой имеют одинаковые идентификаторы. Можно провести аналогию с XML в котором у каждого узла есть дочерние узлы имеющие некоторое имя. Тоесть именем объекта в пределах некоторого узла выступает идентификатор этого объекта.
Пользовательские классы удобно наследовать от класса GenericComponent. У каждого GenericComponent есть свойство DomainContext. Это свойство возвращает эеземпляр класса DomainContext представляющий базу данных модуля Cerebrum.Integrator Метод GetChildComponents доступен из нутри пользовательского объекта и возвращает экземпляр класса, реализующий интерфейс IContainer. Это позволяет проводить разадресацию указателей на дочерние объекты из нутри пользовательского экземпляра не имея доступа к объекту оболчке возвращаемому AttachConnector/CreateConnector.
Для удобства работы в Cerebrum реализованны коллекции объектов, называемые таблицами. Таблицы позволяют редактировать аттрибуты (скалярные объекты 3 го уровня) объектов-строк (warden объекты 2го уровня).
Итак в пределах некоторого узла возможно содание дочерних объектов, адресуемых в пределах этого узла некоторыми NativeHandle. Эти ид могут быть одинаковыми для разных дочерних объектов в пределах разных родительских объектов. Это позволяет устанавливать реляционную связь (по значению) между дочерними объектами разного уровня разных родительских объектов.
При создании аттрибутов создаются экземпляры объектов AttributeDescriptor как дочерние объекты корневого объекта БД. Этим объектам присваиваются уникальные в пределах корневого объекта значения ИД получаемые с помощью sector.NextSequence() Далее пользуясь этими ИД как именами экземпляров объектов второго уровня упользовательских объектов создаются аттрибуты имеющие ИД равные соответсвующим дескрипторам аттрибутов.
Таблица есть две коллекции объектов — объектов аттрибутов и объектов компонентов. Она автоматизирует процесс присвоения объектам значений аттрибутов на основе идентификаторов описателей аттрибутов. Таким образом экземпляры пользовательских объектов имеют дочерние объекты с одинаковыми ИД аттрибутов.
Если когото заинтересовала такая ОБД, то текущую версию можно скачать по адресу
http://www.shuklin.com/ai/ht/ru/cerebrum/
Добавлено форматирование. IT.