Analysis Patterns 1.0 Help

5. Обращение к объектам

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

Простейшим идентификатором объекта является имя (5.1) — последовательность символов, которая обычно идентифицирует объект. Проблема в том, что имена не гарантируют, что они будут относиться к конкретному объекту при любых обстоятельствах. Может потребоваться более искусственное создание: идентификатор в контексте схемы идентификации (5.2).

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

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

Ключевые понятия

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

5.1 Имя (Name)

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

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

Что такое имя? Это неформальный способ идентификации объекта. Я подчеркиваю слово «неформальный», поскольку имена в большей степени зависят от удобства использования, чем от каких-либо других характеристик. Строка «Мартин» — это полезный идентификатор, которого во многих контекстах достаточно, чтобы идентифицировать меня. Но однажды я жил в одном доме с другим человеком по имени Мартин. Оба жильца пользовались этой строкой символов, поэтому ее ценность как идентификатора уменьшилась. Среди нашего круга друзей «Мартин» по-прежнему был наиболее часто используемым идентификатором для нас обоих, но иногда путаница все же случалась. Во многих приложениях мы считаем разумным называть человека единственным именем, как показано на рис. 5.1, хотя это имя может быть структурированным. В более сложных примерах можно дать человеку много имен, чтобы обеспечить возможность псевдонимов, как показано на рисунке 5.2. Например, ко мне можно обращаться по строке «Мартин Ф», чтобы отличить меня от другого Мартина.

5.1.png

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

Рисунок 5.1. Объект с одним именем.

5.2.png

Это модель объекта с псевдонимами. В качестве варианта можно использовать одно (обычное) имя и несколько псевдонимов.

Рисунок 5.2. Объект с множеством имен.

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

Есть еще один аспект имен и идентификаторов, о котором важно помнить: имя — это компактный способ рассказать кому-то об объекте. Оно может описывать некоторые свойства объекта. Называя модель автомобиля 16GL, вы сообщаете кому-то о размере двигателя и уровне комфорта. Хотя это название компактно сообщает о модели, оно не является идентификатором, потому что многие модели могут называться 16GL.

Истинный идентификатор обладает несколькими свойствами: он должен надежно приводить пользователя к одному и только одному объекту и всегда приводить к одному и тому же объекту, когда бы он ни использовался. На рисунке 5.3 показана общая модель идентификатора. В отличие от обычного случая с фундаментальными объектами, отображение (маппинг) на объект является однозначным.

5.3.png

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

Рисунок 5.3. Идентификатор для объекта.

5.2 Схема идентификации (Identification Scheme)

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

5.4.png

Рисунок 5.4. Схемы идентификации.

Пример: В Международной классификации болезней Всемирной организации здравоохранения для диабета I типа используется код E10. Это можно представить как идентификатор со строкой 'E10', схемой идентификации МКБ-10 и объектом заболевания — сахарным диабетом I типа.

Пример: Предположим, у меня есть паспорт с номером 123456. Это представлено в виде идентификатора со строкой '123456', схемы идентификации «Британский паспорт» и объекта «я». Однако в зависимости от ситуации объектом может быть мой паспорт.

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

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

Рассмотрим ограничение уникальности на сопоставление схемы идентификации и строки. Такое ограничение гласит, что никакие два идентификатора не могут иметь одну и ту же схему идентификации и одну и ту же строку. Поскольку отображение идентификатора на объект является однозначным, комбинация схемы идентификации и строки идентифицирует один объект — именно то, что нам нужно. Стоит рассмотреть и другие возможности. Как насчет ограничения уникальности для объекта и строки? Это ограничение гласит, что конкретный объект и конкретная строка уникально ссылаются на схему идентификации; другими словами, объект не может иметь одну и ту же строку в двух разных схемах идентификации. Этот тип ограничения уникальности не только неисполним, но и неудобен. Люди часто предпочитают использовать одну и ту же строку для разных схем, чтобы не запоминать слишком много идентификаторов. PIN-коды банковских карт и номера социального страхования — два примера.

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

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

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

Обычно схема идентификации отвечает за проверку формата строк, используемых в ее идентификаторах. Эта проверка выполняется при создании идентификаторов. Если строка содержит какую-либо значимую информацию об объекте, на который ссылается, то эта информация также должна быть проверена. У меня может быть идентификатор U123, где U означает, что я живу в Соединенных Штатах. Этот идентификатор создаст проблему, если я вернусь в Англию. Вообще, встраивать информацию о характеристиках объекта в идентификационную строку — плохая практика, поскольку такая практика подразумевает, что строка должна меняться при изменении характеристик. Лучше генерировать отдельную строку, предоставляющую такую компактную информацию.

5.3 Слияние объектов (Object Merge)

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

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

Я изложу три стратегии для этого: копирование и замена, замещение, сущность/внешний вид.

5.3.1 Копирование и замена

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

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

5.3.2 Вытеснение

Вторая стратегия заключается в вытеснении объекта, как показано на рисунке 5.5. Один объект классифицируется как вытесненный и связывается с другим активным объектом. В будущем вся работа будет выполняться с активным объектом, а вытесненный объект будет храниться для исторических целей. Нет необходимости заменять ссылки на вытесненный объект. Либо данные, находящиеся в вытесненном объекте, копируются в активный объект, либо все сообщения активному объекту должны проверять данные обо всех объектах, которые получатель вытесняет. Все сообщения вытесняемому объекту передаются активному объекту. Если все данные скопированы, то активный объект может спокойно игнорировать наличие вытесненных объектов.

5.5.png

Рисунок 5.5. Объект, вытесняемый другим.

Пример: При использовании стратегии вытеснения объект JS777 помечается как вытесненный, а JS123 — как активный. Любые сообщения, отправленные на JS777, передаются на JS123.

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

Концептуально стратегии копирования и замены и вытеснения во многом совпадают. Единственное различие заключается в том, что вы можете посмотреть, что изначально было прикреплено к вытесняемому объекту. Это может быть очень важно: если в больнице проводили лечение мистера Смита, не понимая, что эти два пациента — одно и то же, только стратегия замещения даст точное отражение того, что произошло.

5.3.3 Сущность/внешний вид (Essence/Appearance)

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

5.6.png

Рисунок 5.6 Сущность и внешний вид объекта.

Пример: С помощью стратегии «сущность/внешний вид» создается новый объект-сущность с JS123 и JS777 в качестве его внешнего вида.

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

Выше рассматривалось слияние объектов, однако впоследствии слияние может потребоваться отменить. Объединив двух пациентов, больница через несколько месяцев может обнаружить, что на самом деле это были два разных пациента. Разделить объекты заново проще всего, если использовалась стратегия «сущность/внешний вид», поскольку она сохраняет исходные объекты. Таким образом, стратегия «сущность/внешний вид» является наилучшей для использования в случае, если слияние не будет определенным в долгосрочной перспективе.

Пример: Если выяснится, что два Джона Смита все-таки разные, необходимо удалить объектную сущность, связывающую их вместе.

5.4 Эквивалентность объектов (Object Equivalence)

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

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

5.7.png

Рисунок 5.7 Эквивалентность объектов.

Пример: Многие врачи считают, что гепатит G и гепатит GBC — это одно и то же заболевание, но это не универсально. Это можно представить в виде эквивалентности между этими двумя заболеваниями. Если врачу нужен список пациентов, страдающих от гепатита G, и этот врач является участником эквивалентности, то ему также будут возвращены пациенты, страдающие от гепатита GBC.

Ссылки

  1. Martin, J. and J. Odell. Object-Oriented Methods: A Foundation. Englewood Cliffs, NJ: Prentice-Hall, 1995.

Last modified: 16 January 2025