Руководство разработчика

Физические объекты

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

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

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

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

1. C передачей ответственности "справа налево"

В этой модели ответственность за физическое представление передается от объекта-источника копирования объекту-приемнику.

Например, если объекту x1 присваивается значение объекта x2 (x1 = x2), то объект x1 теряет связь со своим физическим представлением и связывается с физическим представлением объекта x2. Рассмотрим для примера случай, когда физическим представлением объекта является файл. Пусть объект файл1 связан с файлом example1.txt, а объект файл2 - с файлом example2.txt. Тогда оператор присваивания файл1 = файл2 приведет к следующей последовательности действий:

  1. файл example1.txt будет закрыт;
  2. объект файл2 потеряет связь с файлом example2.txt;
  3. объект файл1 получит связь с файлом example2.txt.

В результате объект файл1 будет связан с файлом example2.txt, а объект файл2 не будет связан ни с каким файлом. Копирование содержимого файла example2.txt в файл example1.txt или создание дубликатов файлов на диске в ответ на копирование объектных значений в языке, очевидно, выглядит абсурдно.

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

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

2. Закрытая модель

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

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

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

3. С копированием физического представления

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

Если объект x1 присваивается значение объекта x2, то физическое представление объекта x2 копируется в физическое представление объекта x1. В случае, когда объект x1 имел физическое представление, то оно разрушается перед началом копирования.

Например, объект arr1 связан с физическим представлением массив1, а объект arr2 - с физическим представлением массив2. Тогда оператор присваивания arr1 = arr2 приведет к следующей последовательности действий:

  1. объект arr1 потеряет связь с физическим представлением массив1;
  2. будет создана копия объекта массив2;
  3. объект arr1 получит связь с копией объекта массив2.

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

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

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

Поддержка сериализации

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

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

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


См. также: