Структуры данных со свойствами программы

Как известно, база данных — это хранилище структурированной информации, пассивное по своей сути. Бизнес-логика приложения реализуется где-то вне базы, в виде «набора действий для достижения требуемого результата». В случае внесения изменений в хранимый набор данных результатом должно стать новое состояние базы. В краткой форме это можно записать как-то так: событие → {действия} → результат. Изменим эту формулировку на: событие → правила → результат, и посмотрим, что из этого получится.

Если предметная область автоматизации представляет собой систему взаимодействующих значений, то ее можно описать ER-моделью, которая образована экземплярами всего четырех абстрактных сущностей: класс данных, атрибут класса, отношение классов и связь атрибутов. Такая модель не только образует логическую структуру базы данных, но обладает всеми свойствами программы, каковой по сути и является — в вычислительной среде, образованной методами упомянутых абстрактных сущностей.

Рассмотрим это смелое утверждение более подробно, начиная с самых общих определений. (Нижеследующий повтор общеизвестного необходим как минимум для обозначения смысла используемых терминов. Будет сухо и нудно — как и в любом другом теоретическом материале. Чтобы его слегка оживить, в текст вкраплены примеры.)

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

Классы и атрибуты


Класс данных выражает собой отдельную понятийную сущность рассматриваемой предметной области и характеризуется пользовательским наименованием этой сущности. В свою очередь, любая понятийная сущность обладает некоторым уникальным набором собственных характеристик/свойств. Атрибут класса выражает собой отдельную характеристику сущности, именован пользовательским наименованием этой характеристики, обладает типом, определяющим множество (домен) допустимых ее значений, и выступает в качестве фабрики конкретных значений характеристики в объектах класса.

Соответственно, класс данных владеет набором атрибутов (класса), который он хранит в формате кортежа. Выступая в качестве фабрики объектов, класс формирует содержимое объекта в виде кортежа значений, который является экземпляром, производным от кортежа атрибутов. При этом каждое значение в кортеже значений объекта класса является экземпляром, производным от соответствующего атрибута класса.

Таким образом, вполне конкретная предметная область, существующая в виде множества объектов с их значениями, на уровне абстракции описывается системой классов с их атрибутами. И при этом данные и метаданные представляют собой персистентную структуру данных, хранимую в объектной базе данных.

Отношение классов


В основу реализации связи объектов данных положен принцип симметрии. В соответствии с этим принципом связываемые объекты взаимно обмениваются своими идентификаторами. Идентификатор объекта (дескриптор IDO) глобален в пределах физической базы данных, и представляет собой простое целое число.

На уровне абстракции связь объектов описывается отношением классов. Декларация отношения реализуется созданием атрибута в каждом из двух связываемых отношением классов, которые взаимно адресуют друг друга. Каждый из атрибутов отношения типизирован оппозитным классом отношения (каждый класс считается самостоятельным пользовательским типом данных), вследствие чего доменом значений ссылочного атрибута является множество дескрипторов объектов оппозитного класса.

Отношение классов устанавливает меру количественного взаимодействия производных объектов этих классов. При всей простоте этого определения, отношения обладают столь разнообразным функциональным поведением и взаимной логической зависимостью, что эта обширная тема будет рассматриваться отдельно.

Пока же стоит упомянуть, что в отношении один-к-одному оба ссылочных атрибута абсолютно равноправны, а их значением в объектах данных будет единственный дескриптор партнера по связи. В отношении многие-к-одному атрибуты очевидным образом не равноправны: ни по формату хранимого значения, ни по порядку формирования значения. Если на стороне многие- значением атрибута [прямой ссылки] по-прежнему будет единственный дескриптор, то на стороне -один, как следствие строго соблюдения ссылочной симметрии, значением атрибута [обратной ссылки] будет множество дескрипторов, представляющее собой список вида ключ-значение. При этом значение атрибута обратной ссылки производно от значения атрибута прямой ссылки. Механизм реализации этой производности будет подробно рассмотрен ниже по тексту.

Связь атрибутов


Под взаимодействием значений понимается их причинно-следственная функциональная связь. Эта связь существует только на понятийном уровне абстракции, где она принимает вид виртуального соединителя двух атрибутов. По аналогии с отношением классов, декларация связи атрибутов реализуется созданием двух сокетов (параллель с TCP-сокетами вполне уместна), каждый из которых принадлежит своему атрибуту, и размещается в его кортеже сокетов.

Отдельный сокет, описывающий свойства связи со стороны своего атрибута, является такой же персистентной структурой данных уровня абстракции, как класс и атрибут. Как и атрибуты отношения, сокеты, образующие соединитель, взаимно адресуют друг друга. Для этих целей декларация сокета содержит комплексный идентификатор (класс+атрибут+сокет) оппозитного сокета соединителя. Также декларация сокета содержит набор флагов, управляющих передачей и приемом значений через соединитель.

Кортеж


Логически, кортеж представляет собой простое перечисление однородных (с точки зрения кортежа) элементов, содержащих некоторое количество байт данных. Знания о содержимом и способах его формирования лежат за пределами кортежа. Кортеж лишь предоставляет место для размещения и долговременного хранения. Особенности внутренней реализации кортежа были рассмотрены здесь.

Элемент кортежа однозначно идентифицируется своим местом (порядковым номером) в кортеже, которое не изменяется никогда. При добавлении в кортеж, новый элемент занимает свое место раз и навсегда.

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

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

Система идентификации


Неизменность места, занимаемого элементом в кортеже, лежит в основе системы внутренней идентификации объектных сущностей, которая в самом общем виде выглядит так:

lrrxg93ykpyqbjak0nece8fo8zg.png


Каждая объектная сущность идентифицируется своим дескриптором — порядковым номером в соответствующем кортеже: IDC — класс, IDA — атрибут, IDS — сокет, IDO — объект (логически DAT объектов также следует рассматривать как кортеж). Логика также подсказывает, что классы являются элементами кортежа, специфичный владелец которого рассматривается в статье, посвященной отношениям классов.

Модели и мета-сущности


Что примечательно — на уровне абстракции существуют сразу две модели, образованные различными сущностями этого уровня.

Совокупность хранимых деклараций классов, атрибутов и сокетов образует модель данных. Модель данных считается исполнительной, так как образующие ее сущности выполняют в отношении уровня данных функции фабрики объектов (класс) и фабрики значений (атрибут).

Модель приложения является виртуальной, и существует на правах формы представления модели данных. Модель приложения динамически создается визуальным конструктором, который использует ее для отображения существующей модели данных, и создания в ней новых деклараций, путем создания новых сущностей модели приложения. В образовании модели приложения, наряду с вещественными классом и атрибутом, принимают участие такие виртуальные сущности как отношение и соединитель. Виртуальные сущности не образуют хранимых деклараций, а создаются динамически из деклараций атрибутов и сокетов, частично инкапсулируя факт их существования. Виртуальных характер модели приложения ничуть не мешает рассматривать ее в качестве первичной модели предметной области.

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

Стоит лишний раз подчеркнуть, что все методы конструирования, с помощью которых создаются и изменяются обе модели (данных и приложения), а также все без исключения методы исполнения, используемые моделью данных применительно к объектам и значениям уровня данных, принадлежат сущностям уровня мета-определений. Уровень же моделей, обеспечивающий создание и исполнение всей бизнес-логики приложения, образован исключительно декларативными экземплярами мета-сущностей, и не содержит в себе исполняемого кода.

Методы исполнения


Методы конструирования, с помощью которых создаются экземпляры мета-сущностей и переопределяются значения тех или иных их свойств, представляются достаточно очевидными, и не требуют комментариев. Чего нельзя сказать об образующих пресловутую вычислительную среду методах исполнения, с помощью которых воздействия извне изменяют состояние данных в соответствии с правилами, декларированными в форме модели данных. Собственно говоря, вызов метода исполнения и является таким внешним воздействием. Всего же таких методов четыре: Create, Set, Get и Update.

Метод Create принадлежит мета-классу, и используется для создания производного объекта класса. Параметром метода является дескриптор IDC целевого класса. Метод Create создает объект как экземпляр кортежа атрибутов указанного класса, и регистрирует его в таблице аллокации DAT за очередным свободным дескриптором IDO.

Методы атрибута: Set, Get и Update, принадлежат мета-атрибуту, и позволяют оперировать значениями объектов данных. Метод Set отвечает за присвоение значения, метод Get — за выборку значения, а метод Update является событием, инициирующим атрибут на пере-формирование производного хранимого значения (смысл этого действия станет понятным несколько позже).

Для методов атрибута целевой объект идентифицируется дескриптором IDO, а собственно целевое значение доступно исключительно через атрибут класса, путь к которому представлен в дескрипторах IDC+IDA модели данных. Иными словами, все действия над значением совершаются от лица атрибута класса. Особенностью процесса исполнения методов атрибута является то, что в его ходе каждый из методов прибегает к перебору сокетов в кортеже атрибута, с вызовом аналогичного метода для целевого атрибута, адресуемого соединителем, при условии что в сокете установлен одноименный методу флаг.

Так как исполнение любого из трех методов: Create, Set или Update, изменит состояние данных, то их вызов возможен только в контексте транзакционной сессии. Вызов любого из этих трех методов является атомарным внешним воздействием на базу данных, которое легко формализуется в формат транзакции, с ее последующим сохранением в журнале.

Рассмотрим логику исполнения методов атрибута чуть более подробно.

Присвоение значения


Итак, вызван метод Set, которому передали адресные параметры, и указатель на присваиваемое значение (*value). В теле этого метода атрибут сформирует новое значение, выполнит его присвоение соответствующему элементу кортежа объекта, а далее начнет последовательный перебор сокетов из своего кортежа. Для каждого сокета, у которого установлен флаг Set [S], исходный атрибут вызовет метод Set применительно к атрибуту, путь к которому прописан в декларациях сокета. Отметим, что исполнение метода может завершиться досрочно, без обхода кортежа сокетов, если новое значение эквивалентно хранимому.

gwo-txqvvs80guwef3zpaq-ypre.png


Делая производные вызовы Set, атрибут следует принципу изоляции — «выстрелил, и забыл», не заботясь о последствиях. Дальнейший ход событий определяется уже другими действующими лицами-атрибутами. При этом, что важно, транзакционный характер исполнения обеспечивает перманентную согласованность всех изменяемых значений, независимо от объема и «протяженности» изменений.

Рассмотрим формирование производного значения на примере из жизни счетов и накладных:

5dj6ahycuzhgt-p11ks4k2ikcri.png


На схеме контурными стрелками обозначен пользовательский ввод значений, он же внешний вызов Set. Любое изменение значений атрибутов Количество или Цена активно передается атрибуту Сумма, который для формирования производного значения использует функционал, в данном случае — мультипликативный.

Функционалы — это предопределенные (для каждого типа значения) методы мета-атрибута, которые позволяют сформировать результирующее значение преобразованием значений-аргументов, полученных через соединители от одного или нескольких атрибутов-источников. Атрибуту назначают функционал путем присвоения его дескриптора (IDF), который представляет собой порядковый номер в общем списке функционалов.

Если атрибуту назначен функционал, то все вызовы Set и Get в адрес атрибута обрабатываются этим функционалом, при необходимости — с дополнительным опросом (Get) источников. Обратим внимание: для исключения первоисточника вызова из опросов, адресная часть вызова (IDC+IDA) перманентно включает в себя также и дескриптор сокета-получателя (+IDS).

Зависимый соединитель


Оба соединителя из приведенного выше примера были использованы в простой безусловной форме.

Между тем, функциональное поведение соединителя можно поставить в зависимость от действующих значений сторонних атрибутов, которые для исходного соединителя образуют своего рода »контекст исполнения». Для реализации связи с атрибутами-контекстами, в декларациях сокета предусмотрена возможность адресации трех дополнительных, так называемых »контекстных» сокетов. У каждого контекстного сокета есть свое, строго фиксированное назначение-аспект: блокирующий (lock), ссылочный (ref) и ключ (key), но вместе с тем это точно такие же экземпляры мета-сокета, как и »базовые» сокеты соединителя. Для адресации каждого контекстного сокета базовому достаточно двух дескрипторов: IDA+IDS.

580szluuncvatj0o3dt_apghsiu.png


Блокирующий lock-сокет разрешает передачу значения по соединителю, если возвращаемое им значение актуально, и блокирует в противном случае. Под актуальным понимается инициализированное значение атрибута-владельца сокета (lock-контекст), которое дополнительно оценивается еще и с точки зрения его типа: true для логики, не ноль для числа, и присутствует хотя бы один литерал (помимо пробела) для строки.

Ссылочный ref-сокет используется во внешних соединителях, связывающих атрибуты разных классов. Он предоставляет соединителю дескрипторы IDO объектов данных другого класса, используя в качестве источника значений соответствующий атрибут отношения (ref-контекст) в своем классе.

«Ключевой» key-сокет предоставляет соединителю значения ключа, и необходим для реализации работы со списками. В качестве источника значения ключа (key-контекст) по умолчанию используется базовый атрибут класса.

Без учета специфики ссылочного и ключевого аспектов, логика взаимодействия контекстных сокетов с базовым едина для всех трех контекстов. Так базовый сокет на каждой из сторон соединителя немедленно прервет исполнение текущего метода Set | Get, если хотя бы один из его действующих (то есть фактически декларированных и сохраняющих актуальность) контекстов содержит не актуальное значение. Иначе говоря, ref- и key- контексты перманентно обладают также свойствами lock-контекста. В этом нет ничего удивительного, если вспомнить, что значение любого типа можно привести к логическому типу.

Методы сокета


Инициация условного соединителя со стороны его контекстов осуществляется путем вызова одного из двух внутренних методов исполнения: Reset и Unset, принадлежащих мета-сокету. Эти методы вызываются атрибутом-контекстом в ходе исполнения метода Set в адрес базового сокета соединителя по следующим правилам. Если текущее значение атрибута актуально, то перед любым его изменением атрибут вызовет метод Unset для всех своих сокетов, у которых установлен флаг Unset [U]. Далее, после присвоения нового значения, в повторном цикле обхода кортежа для вызова производных методов Set, атрибут вызовет метод Reset для тех своих сокетов, у которых установлен флаг Reset [R]. Иными словами, атрибут выполняет имитацию сначала де-инициализации своего действующего значения, со всеми вытекающими из этого последствиями для внешнего окружения атрибута, а затем выполняет инициализацию уже новым значением.

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

Для большей наглядности проиллюстрируем сказанное примерами.

Примеры исполнения


Рассмотрим использование ссылочного ref-аспекта на следующем примере: Накладная в атрибуте Итого обобщает значение атрибута Сумма всех своих Записей. Здесь и далее на подобных схемах вертикальная линия разделяет пространства связанных отношением классов, а выступ на ней обозначает меру количественного взаимодействия классов как многие-к-одному. В нашем примере многие- это Запись.

t-l5mhi93hv6tsmkfgzaaflracg.png


Атрибут [Н] является атрибутом прямой ссылки отношения Записи с Накладной. В случае реализации отношения этот атрибут получает в качестве значения дескриптор IDO объекта Накладная.

При любом своем изменении значение Сумма активно передается атрибуту Итого, при этом базовый сокет соединителя использует декларацию ссылочного ref-сокета для обращения к атрибуту [Н]. Извлеченное ref-значение будет использовано в качестве адресного параметра (как указатель на целевой объект) метода Set, вызываемого в адрес атрибута Итого. Если же отношение не реализовано, производный Set не будет вызван.

При получении значения атрибутом [Н], последний методом Reset инициирует базовый сокет на вызов метода Set, значащими параметрами которого будет пара NUL → [текущее значение Суммы]. Если затем де-инициализировать значение [Н] (разорвать отношение), то атрибут методом Unset инициирует базовый сокет на вызов метода Set с параметрами [текущее значение Суммы] → NUL. Что приведет к тому, что текущее значение Суммы будет «изъято» из текущего значения атрибута Итого.

Обратим внимание: аддитивный функционал атрибута Итого «умеет» корректно изменять результирующее значение, получая на вход изменение значения атрибута-аргумента. Такое поведение, характерное для так называемых «ленивых» вычислений, лежит в основе реализации всех естественных функционалов. Применительно к приведенному примеру, атрибуту Итого нет необходимости прибегать к опросу Get всех частных Сумм при изменении какой-либо одной, ему достаточно учесть величину и направление изменения.

Возвращаясь к примеру: если уже инициализированный ранее ссылочный атрибут [Н] получит новое значение (Запись изымается из одной Накладной, и включается в состав другой), то этот атрибут вызовет Unset перед изменением, и Reset после изменения. Тем самым Сумма записи будет изъята из Итого первой Накладной, и добавлена в Итого второй. При любой комбинации внешних воздействий, система перманентно сохранит логическую согласованность значений.

Для иллюстрации работы блокирующего аспекта попросту дополним предыдущий пример: пусть по каждой товарной позиции предусмотрена фиксированная скидка, которая может быть выключена вручную.

3l0a9bkna3j7pv61bezna7cuwvi.png


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

Следующий пример иллюстрирует работу key-контекста соединителя: объекты класса Запись формируют список курсов Валюты, который затем используется для выполнения обменных Операций с этой валютой.

pyhhlyr9cpgixc_heus17zj9prs.png

Атрибуты Дата в классах Запись и Операция являются источником ключа — key-контекстом для соответствующего соединителя.

Атрибут Курс в классе Валюта хранит список, образованный парами Дата: Курс, который формируется назначенным атрибуту списковым функционалом из значений, которые активно (методом Set) передаются ему по соединителю из класса Запись. Отметим, что в параметрической части методов Set и Get под указатель на значение ключа перманентно выделено отдельное место.

В классе Операция атрибут Курс, используя в методе Get значение Дата как ключ, извлекает соответствующее значение из списка. Сам Get при этом инициируется активным методом Reset, порожденным изменением значения: или атрибута Дата или ссылочного атрибута, указателя на объект Валюта (соответствующий ссылочный атрибут на рисунке не показан).

Активность соединителя


Обратим внимание: в предыдущем примере соединитель Курс.[Валюта] → Курс.[Операция] не является активным, так как на стороне атрибута-источника не установлен флаг [S]. Соответственно, никакие изменения в списке курсов не будут активно транслироваться в уже имеющиеся Операции. Тем не менее, изменение значения любого из контекстов соединителя условно «активирует» его, так как сопровождается вызовом активных методов Reset | Unset. И хотя сам Get пассивен, тем не менее возвращенное им значение будет присвоено атрибуту Курс в ходе исполнения исходной транзакции на изменение Даты или ссылки на Валюту.

Соединитель, обладающий [S] флагом, является безусловно активным соединителем. Соединитель, лишенный собственной активности, но при этом обладающий активными контекстами (на что указывают флаги [R] и [U] в его контекстных сокетах) в дальнейшем называется полу-активным соединителем.

Соединитель, обладающий только флагом Get, считается пассивным соединителем. Если же у соединителя сбросить все флаги, то это равноценно его полному удалению из модели. И обратим внимание: именно флаг Get определяет не упомянутое ранее, но такое важное свойство соединителя как вектор передачи значения.

Логическая согласованность


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

Но активный соединитель применим далеко не всегда. Чуть выше был приведен пример с курсами валют, в котором значение Курс.[Операция] будет согласовано с источником только на момент последнего срабатывания контекстов. И если на заданный день значение курса в списке курсов (Курс.[Валюта]) изменится, то это изменение само по себе уже не повлияет на хранимое значение Курса в Операции.

К тому же, не стоит забывать и о нештатных ситуациях. Например, когда функционально зависимый атрибут создается уже после того, как были сформированы значения атрибутов-аргументов. В этом случае восстановить согласованность данных можно только, а принудительном порядке, используя Update.

Событие Update


Исполнительный метод Update, принадлежащий мета-атрибуту, предназначен для принудительного восстановления согласованности значений. Вызов этого метода в адрес атрибута указанного объекта данных, заставляет атрибут заново сформировать свое хранимое значение из значений атрибутов-аргументов в текущий момент времени.

Стоит отметить, что на практике бывают вполне конкретные ситуации, когда рассогласованность значений является следствием условий и правил реализации прикладной задачи. В этих ситуациях метод Update следует использовать как инструмент Событие реального времени прикладной задачи. Например, некоторое производное значение требуется сформировать внешним событием по состоянию на выбранный момент времени, и зафиксировать его в этом состоянии.

Реверс значения


В самом первом примере, там где Количество и Цена активно образуют Сумму, обратим внимание на следующий факт: атрибут Сумма, в отличие от Количества и Цены, не может получить свое значение извне, внешним вводом. Этот явный запрет обусловлен требованиями согласованности и непротиворечивости данных, которые очевидным образом будут нарушены вводом в общем-то произвольного значения, не соответствующего действующим аргументам. Поэтому, при наличии активных внешних соединителей, атрибут автоматически теряет способность к интерфейсной редактируемости производных значений.

Между тем, эту способность можно восстановить, разрешив атрибуту реверс введенного значения в один из атрибутов-аргументов. Иными словами, нужно выбрать получателя корректирующего значения, а именно — соединитель, в который будет осуществлен реверс. В нашем примере представляется логичным, если получателем коррекции будет выбран атрибут Цена, для соединителя с которым разрешается вызов метода Set со стороны Суммы путем установки соответствующего флага [S] в Get-сокете, как показано на рисунке.

bpzy7sfhopqa9yujp5yuzd7kny4.png


Отметим, что собственно исполнителем реверсивной передачи значения всегда является функционал атрибута, обладающий соответствующим алгоритмом для вычисления значения коррекции. Целевой атрибут для передачи он определяет через сокет, у которого флаги [S] и [G] установлены одновременно.

Реверс значения может быть реализован в адрес любого атрибута, обладающего способностью принять значение извне, и в том числе такого атрибута, который сам получил эту способность за счет включения реверса:

lvzqkeuoj5jaqdnpxyjgmnwjikc.png


Получив ввод извне, атрибут Итого использует список обратных ссылок для реверсивной раздачи своего изменения атрибутам Сумма для всех объектов Работа из списка обратных ссылок (ref-контекст). Не стоит думать, что приведенный пример лишен практического смысла: здесь стоимость работ подгоняется под предельную сумму, озвученную заказчиком. Впрочем, стоит привести еще один пример распределения значений, также основанного на механизме реверса.

svnhpz4va6viixa1qifi2jms54o.png


В каждом из классов атрибут Часы используется в качестве key-контекста к реверсивному соединителю, обеспечивая его тем самым базисными значениями для пропорционального распределения значения Сумма.

Инверсия сокета


Сокет обладает свойством инверсии, которое включается установкой флага Inverse. Смысловое назначение и применение этого свойства различно для сокетов на разных сторонах соединителя.

Так если флаг инверсии установлен исходящему базовому сокету или контекстному сокету, то передаваемое через этот сокет значение будет инвертировано: положительное число станет отрицательным, а логическое значение изменится на противоположное.

5ojlw8ppcbi6c2zibwp78hdynvy.png


Установка флага инверсии для входящего (Get-) сокета соединителя изменит операционное поведение функционала атрибута. Так значение, полученное через инверсный сокет, мультипликативный функционал числа будет рассматривать как делитель, а не как сомножитель. Аналогичным образом значение, поступившее через инверсный сокет, будет рассматриваться аддитивным функционалом как вычитаемое.

Реализация отношения


Самое примечательное состоит в том, что технология соединителей в полной мере используется также и для обеспечения внутренних потребностей самой модели данных. И в частности — для реализации взаимного обмена идентификаторами производных объектов классов, в рамках декларации отношения между этими классами и в соответствии с требованиями ссылочной симметрии. Ссылочные атрибуты, образующие отношение классов, очевидным образом находятся в прямой причинно-следственной зависимости, которая в модели данных выражается декларацией соединителя.

Помимо соединителя, для реализации отношения используются и так называемые служебные атрибуты. Эти атрибуты, выполняющие определенные утилитарные функции, декларированы непосредственно в кортеже мета-класса, а следовательно присутствуют в кортеже каждого пользовательского класса.

Источником значения для ссылочного соединителя является служебный атрибут Own. Этот атрибут типизирован дескриптором собственного класса. Когда класс создает производный объект, то в качестве значения атрибута Own он сохраняет дескриптор IDO этого объекта.

Еще один служебный атрибут — Del, по умолчанию используется в качестве lock-контекста для всех без исключения исходящих внешних соединителей, связывающих атрибуты разных классов. Эта декларация обеспечивает адекватное поведение удаляемого объекта, а именно — изъятие (Unset) значения атрибутов-аргументов из значений атрибутов-получателей, локализованных в других классах.

Ну, а собственно сам ссылочный атрибут выступает в качестве ref-контекста активного ссылочного соединителя, предоставляя ему дескриптор IDO целевого объекта.

Значение списка обратных ссылок формируется списковым функционалом из пар ключ-значение, где значением является IDO объекта-владельца прямой ссылки, а в качестве источника ключа (key-контекст) по умолчанию используется базовый атрибут класса. Таким образом, формирование списка обратных ссылок по сути ничем не отличается от формирования списка курсов из примера выше, в котором lock-контекст Del, и ref-контекст [B] также присутствуют, но не были показаны на схеме.

qckyqnkk7j3anvzbcn2nfysvecs.png


Стоит лишний раз подчеркнуть, что вся эта конструкция, включающая в себя служебные атрибуты и ссылочный соединитель, создается конструктором отношения автоматически.

Функциональность соединителя


Несмотря на наличие у сокета соединителя методов Unset/Reset, собственной функциональностью соединитель не обладает. Логически связывая атрибуты, соединитель является всего лишь декларацией наличия и характера причинно-следственной зависимости производных значений. Реализация же самой этой зависимости осуществляется исключительно методами атрибута. Поэтому, под функциональностью соединителя следует понимать комплексное декларативное свойство описываемой им зависимости.

Будучи сущностью сугубо виртуальной, соединитель образован экземплярами мета-сокета, которые логически связаны между собой взаимной адресацией. Соответственно, характер декларируемой зависимости атрибутов определяется как комбинацией сокетов, образующих соединитель, так и установкой флагов отдельного экземпляра. Отдельный сокет может быть связан с четырьмя другими сокетами, за каждым из которых закреплен строго однозначный функциональный аспект: базовый (оппозитный) (base-), блокирующий (lock-), ссылочный (ref-) и

© Habrahabr.ru