ELIT. ООП и роли

| рубрика: Проектирование | автор: chief_editor
Метки: ,

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

ELIT.Предисловие

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

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

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

ELIT.Семантика

Известно, что "при передаче информации по каналу она искажается". Можно добавить - чем больше преобразований на разных этапах передачи, и чем они сложнее - тем выше вероятность ошибок, и тем сложнее их исправления. Тем более - сложнее модификация "преобразователей". К чему это? В процессе создания программной продукции есть целый ряд этапов и действий, когда разработчик находится только на декларативно-понятийном уровне - общение с заказчиком, создание и согласование ТЗ, написание комментариев, описаний, руководств, хелпов и т.д. При этом он ухитряется находить "общий язык" с самыми разными людьми, разных профессий и опыта. При этом существует ряд других этапов - анализ, проектирование, программирование. Первые два вызывают активные дискуссии и взаимное непонимание даже среди профессионалов отрасли. Не говоря уже о программировании: даже хорошо документированный текст сложен для понимания другими профессионалами. И дело вовсе не только в многочисленности методик, технологий, средств и языков анализа, проектирования и программирования - проблемы возникают даже в рамках "однородных" средств на всех этапах. Главной причиной, по моему мнению, является использование несвойственных человеку средств общения. Человек мыслит понятиями и категориями, сами именования которых (слова) несут в себе конкретный смысл. И даже различные акценты в тех или иных профессиональных, и ограниченных по иным причинам областях, не мешают осознавать родственность понятий, с учетом контекстов самих рассматриваемых областей. Излагаемые подходы предполагают, насколько возможно, использовать органично присущие самому человеку подходы и на этих этапах работы.

Что из этого следует? В системе должны присутствовать механизмы, автоматически регистрирующие все "слова", с учетом их "родственности", контекста применения, разных видов и способов этого применения и, разумеется, способов описания этих "слов", "контекстов" и видов, с конкретными реализациями. Неплохо при этом иметь возможность динамически ограничивать и/или модифицировать применимость и реализации, частично или полностью, без потери общего смысла понятий, как глобально (для системы в целом), так и для одного объекта элементарного типа, и на всех промежуточных уровнях. Т.е. речь идет о некоем языке, работающем на тех же принципах, что и человеческое мышление, с точки зрения декларации понятий и их использования, и о механизмах самой системы, обеспечивающих указанные возможности, о некотором "интеллектном" языке, intElligence Language (EL). Попробую проиллюстрировать сказанное примерами.

declare property sex as boolean

декларация понятия "пол". При этом уже явно указано, что речь идет о некоем свойстве, способном принимать только два конкретных значения. Так как реализующий тип - простой, может иметь лишь два возможных значения, и допускает лишь установку своего значения и его "выдачу" - сама декларация уже содержит реализацию. При этом _любая_ декларация, любого "понятия", сама является собственным "интерфейсом", т.е. в данном случае декларация определяет все необходимое для использования этого свойства. Особо хочу подчеркнуть, что само свойство независимо ни от чего, как и любое "понятие вообще" - оно продекларировано вне каких-либо контекстов, типов и предполагаемых ролей, т.е. "на внешнем уровне". Разумеется, те или иные свойства и понятия могут декларироваться и, тем более, реализовываться, и зависимо. Т.е. для типов, контекстов, ролей. И таких будет большинство.

Еще одна иллюстрация :

declare man, woman, sex
declare sex as property in (man, woman)

Первая строка декларирует три понятия, без уточнения, какие это понятия - "понятия, и все". Предполагается, что они могут быть доопределены позже, в возможно разных ипостасях но, даже если они и не будут доопределены - сама фиксация уже не бессмысленна. Вторая строка доопределяет ранее продекларированное понятие, как свойство, при этом могущее принимать два значения, являющихся понятиями. Про сами man и woman еще ничего не известно - они в дальнейшем могут быть описаны как типы, или как роли, или, как и то и другое (разные описания), или не будут доопределяться вообще: это никак не мешает применению свойства "пол" уже сейчас. Из этого следует, что даже описание и реализация "мужчины" и/или "женщины" сложным типом или ролью вовсе не означает, что в любом объекте, имеющим свойство "пол", должны размещаться пара громоздких объектов. Для реализации достаточно предоставить место лишь для размещения UID самого понятия (слова) в хранилище системы.

Еще одна возможная форма объявления "пола":

declare man, sex are man

предполагает наличие стандартного предиката is (да?)

Pete.sex is man

должен возвращать true.

Логика предполагается тернарная: true, false, unknown. Это позволит, в частности, проверять объекты на наличие требуемых свойств/интерфейсов для определения пригодности их использования в требуемой роли, а также сам факт декларирования понятий и то, в каких смыслах они продекларированы. Да и вообще, от неизвестностей не уйти.

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

ELIT.Свойства, интерфейсы, роли.

Собственно, три вынесенных в заголовок слова - это синонимы, на разных уровнях детализации. Минимальным фиксируемым системой "атомным понятием" является само понятие:

declare world

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

Свойство - следующий уровень общности. В отличие от "чистого" понятия, может требовать те или иные "данные" для реализации. Данные представляют собой либо место для размещения UID другого понятия (любой декларации) - при определении _только_ через понятия, либо один из атомарных простых типов (логический, число, строка и т.д.). Свойства могут "читаться" и "устанавливаться", т.е. тоже являются всеми понятиями следующих уровней детализации, как и "чистое" понятие, а значит, везде могут использоваться непосредственно. Естественно, никакие дополнительные локальные данные для реализации (не являющиеся хранилищем самого свойства) ему не нужны. Примеры декларации свойства приведены в "Семантика-2".

Интерфейс - является тем, как и называется :) Такое же атомарное понятие, как и чистое, и свойство (но уже условно атомарное, контекстное), которому требуется отдельная реализация. Требоваться может в силу использования более одного свойства и/или необходимости неких локальных данных для расчетов и т.д. Так как реализация требуется, м.б. "виртуализирован", т.е. иметь разные, контекстные реализации - основное отличие от ранее описанных понятий. При этом "во внешнем мире" по-прежнему атомарен - само имя его - это и есть "метод". Но ему уже может потребоваться более одного "параметра", которые совпадают с именами используемых интерфейсом свойств. Может выступать в качестве либо интерфейса (в роли) либо в качестве "атомарной роли". Полный перечень используемых свойств должен входить уже в декларацию! Это необходимо для определения полного списка свойств роли, использующей данный интерфейс. Как следствие - на уровне реализаций (виртуализации) список "входящих" свойств меняться не может. Тем не менее, может быть контекстно-декларирован! При этом могут меняться как число свойств, так и их виды/типы. Пример:

declare property center, radius, lefttop, rightbottom // без детализацииdeclare
interface drawdeclare interface draw for circle (center, radius)
declare interface draw for rectangle(lefttop, rightbottom)
implementation(
    interface draw for circle(...)
    interface draw for rectangle(...)
)

В примере circle и rectangle рассматриваются, как контексты, при этом они же являются понятиями, как и "все на свете" и, кроме того, вполне могут "где-то" быть объявлены и реализованы и как типы, что вполне естественно.

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

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

ELIT.Роли, типы и "классы".

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

Собственно, типы и роли - это составные части, совместно и образующие класс, но - на уровне только public-"методов", без "начинки" и public-"полей". Существование последних вообще не предполагается ("полная" инкапсуляция), до начинки (локальных, служебных понятий) доберемся позже. Сейчас - только о "внешнем виде". Для чего мне понадобилось деление одного понятия на два? Краткий ответ - потому, что их два! Если воспользоваться понятием нормализации из теории РСУБД, класс не нормализован, ибо субъект и его роли находятся в отношении "один-ко-многим". С учетом же того, что одну роль могут выполнять разные субъекты, "годные" для исполнения этой роли (по некоему набору критериев), верно и обратное соотношение, т.е. роли и субъекты находятся в отношении "многие-ко-многим". Класс же - понятие "синтетическое", т.е. содержит все данные, необходимые для выполнения всех ролей (избыточность по данным) и в то же время либо содержит интерфейс и данные для всех мыслимых ролей (что просто нереально), либо большинство его потомков в иерархиях наследования в действительности являются лишь ролевой детализацией, (что и имеем в действительности) при этом наследуется "все, что не нужно" в детализированной роли.

Фактически, деление условно. Под типом подразумевается минимальный класс, содержащий минимум самых основных свойств, нужных подавляющему большинству его ролей, "главных", тех, ради [неявной] реализации которых он и декларируется. Разумеется, он сам уже является некоей минимальной ролью, и объект (актер) может создаваться необязательно объединением типа и роли - может быть использован только тип, в своей "неявной" роли. А вот роль в качестве актера не может быть использована! Ибо на актера могут быть возложены и другие роли, при этом необходимо фиксировать факт того, что все назначенные роли исполняет один объект. Связка производится именно по "экземпляру типа". И именно это и является главным отличием типа и роли, помимо самого смысла понятий, естественно.

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

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

Попытка ввести объекты разных по смыслу но одинаковых по именованию (семантике) типов в один контекст вызовет недовольную реакцию инструмента (системы). Никакого другого вида полиморфизма не предусматривается.

И наследование. Наследование, совместно с включением, составляет понятие агрегации. Здесь используется только наследование public- "методов" (т.е. интерфейсная часть - но я уже это слово задействовал) - ни о каких реализациях речь пока не шла вообще. Организуется использованием в декларации предиката is (является). Кроме этого, возможно объединение понятий, т.е. декларация "составного типа" - примером является декларация (не реализация конкретного объекта!) типо-роли:

declare type fidoman as homo in (computerman, student)

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

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

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

Но прежде всего - меня достал мой "интерфейс" - и читателей путает, да и вообще термин не слишком годится - интерфейсами являются и сами продекларированные слова, и свойства, и "интерфейсы", и типы и роли. Объявляется конкурс :) на что-то более удобоваримое для замены слова в кавычках. В том смысле, в котором оно является в письме "свойства, интерфейсы, роли". Итоги желательно подвести до написания письма с формулировками. А до него осталось лишь одно - "Контекст".

ELIT.Контекст

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

Первая роль касается зон и специфики действия самих понятий. При этом понятия в разных контекстах могут как оставаться одноименными, так и менять названия - синонимичность. Пример уже приводился (не мною) - глобальное (для материальных объектов) свойство "высота" для более узкого контекста "человек" естественно именовать уже, как "рост" - for homo height is stature (пример неудачен - рост тоже может писаться, как height :) Здесь приведен пример правила, указывающего на синонимичность понятий. Если в пределах одного контекста действуют объекты с ролями, содержащими свойства, продекларированные в разных смысловых контекстах, приводимых друг к другу - ко всем применимы общие запросы (суперкласса). При этом к конкретному объекту можно обращаться по полному списку его интерфейсов. Возможно существование контекстно-неприводимых одноименных понятий. Например, "стек" в контексте "компьютер" и "стек" в контексте "английский денди в колониальной Индии" :) - явно понятия разные. Если соотношение контекстов никак не определено, при вводе обоих понятий в некий составной объект система либо должна сообщать о неоднозначности, либо проглатывать молча, различая эти понятия, но при этом отвергать общий запрос типа "кто имеет стек", без контекстной детализации "компьютер.стек", к примеру. Собственно, под понятийными контекстами имеются ввиду именно профессиональные и предметные специфики одних и тех же понятий или разные значения одних и тех же (по написанию) слов: квартал в градостроительстве и в бухгалтерском учете - вещи разные, в то время как "объем" (легких) в медицине является лишь специфическим подмножеством "объема" вообще.

Объектный контекст - это просто некий "непростой" тип объекта, состоящий из других объектов и задающий для них те или иные ограничения, [возможно] некие изменения (непринципиальные) в свойствах и устанавливающий правила их возможных взаимодействий. В частности, "температура" вообще имеет диапазон от 0К до миллионов градусов, но в контексте "поликлиники" вряд ли имеют смысл температуры больше 42С и меньше 32С, разве что на градуснике (комнатном или уличном), но это уже другие контексты. Точно также "Вася" и "Маша", являясь просто "человеками", на работе именуются "менеджером" и "бухгалтером", а дома - "мужем" и "женой", "папой" и "мамой". Разумеется, это лишь перечисления их ролей в разных контекстах, но они могут накладывать различия во взаимодействиях, например "именовании" - на работе "Василий Петрович", дома - смотря с кем! - "ты, придурок", или "папахен" :) Объектный контекст описывается перечнем общих для всех правил, правил взаимодействия конкретных объектов (прежде всего - в их ролях), правил применения (и, возможно, даже реализаций) тех или иных свойств и интерфейсов.

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

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

  1. Модульная контекстность достигается делением на файлы, декларацией static для переменных и функций, использованием разных библиотек и т.д.
  2. Объектная - описанием внутри классов, прямым кодом внутри функций и методов.
  3. Понятийная - namespaces, наследованием классов и виртуализацией методов и т.д.

Разница прежде всего в том, что зоны действия и применимость данных "контекстных" механизмов ограниченны, жестко заданы изначально и, естественно, резко недостаточны. При этом для любых изменений/добавлений/расширений приходился ждать изменений стандарта и последующих изменений реализаций :( С учетом времени ожидания и тем, что результаты его не оправдывают... :)))

Осталось попытаться, с учетом уже изложенного, привести определения, диаграммы и т.д. - и можно "отдаться на растерзание" :) Но оставшееся потребует времени :(

Владимир Павликов, июль 1999 (с редакторскими правками, С. Тарасов, 2005)

Оригиналы писем находятся в архиве fido.su.oop.