учебники, программирование, основы, введение в,

 

Динамические структуры: объекты

Объекты
В процессе выполнения ОО-система создает некоторое число объектов. Организация этих объектов и отношения между ними определяют конструкцию времени выполнения. Рассмотрим свойства объектов.
Что такое объект?
Прежде всего, необходимо напомнить смысл термина "объект". Полная ясность была внесена в предыдущей лекции в виде строгого определения (Определение и объективное правило, см):
Определение: объект
Объект - это экземпляр некоторого класса
Во время выполнения программная система, содержащая класс C, может в разных точках, используя процедуры создания или клонирования, создавать экземпляры C, - структуры данных, соответствующие образцу, заданному классом C. Например, экземпляр класса POINT представляет собой структуру данных, состоящую из двух полей, соответствующих атрибутам x и y класса. Экземпляры всех возможных классов составляют множество объектов системы.
Это официальное определение в мире ОО-ПО. Но в повседневном языке термин "объект" имеет гораздо более широкий смысл. Любая программная система связана с определенной внешней системой, которая может содержать "объекты": точки, линии, поверхности и тела в графической системе; сотрудников и их оклады в системе расчета заработной платы и т.д. В таких ситуациях, как правило, реальным объектам соответствуют программные объекты. Примером может служить класс EMPLOYEE в системе расчета зарплаты, экземпляры которого являются компьютерными моделями сотрудников.
Хорошим следствием дуализма слова "объект" является естественность и мощь ОО-метода, применяемого для целей моделирования реальных систем. Это уже отмечалось при рассмотрении принципа Прямого Отображения (direct mapping), который, как отмечалось, является принципиальным требованием модульного проектирования. Неудивительно, что некоторые классы являются моделями внешних типов объектов проблемной области, а экземпляры классов - моделями реальных объектов. (См. "Прямое отображение",)
Но не стоит переоценивать "реальность" слова "объект". В науке и технике существует большой риск в заимствовании слов естественного языка и придания им специального смысла. Термин "объект" настолько перегружен повседневным смыслом, что техническое его использование может стать источником недоразумений. В частности:

  • Не все классы соответствуют типам проблемной области. Многие классы, введенные в интересах проектирования и реализации, не имеют двойников в моделируемой системе. Именно эти классы на практике могут иметь наибольшее значение и именно их труднее всего спроектировать.
  • Некоторые концепции проблемной области естественно приводят к классам, хотя в проблемной области не существует реальных объектов, которые можно было бы поставить в соответствие экземплярам этих классов. Примерами могут быть класс STATE, описывающий состояние системы, или класс COMMAND. курса "Основы объектно-ориентированного проектирования")

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


С учетом наследования O будет тогда косвенным экземпляром других классов, - предков C. Это тема дальнейшего обсуждения; в данной дискуссии достаточно понятия прямого экземпляра. Везде, где не может возникнуть недоразумений, слово "прямой" будет опущено.

Класс C называется порождающим классом (generating class) или просто генератором (generator) объекта O. Заметьте, C- программный текст, а O - структура данных времени выполнения, появляющаяся в результате работы рассмотренных ниже механизмов создания объектов.
Часть компонентов Cявляется атрибутами. Эти атрибуты полностью определяют форму объекта, представляющего собой просто набор полей, по одному на каждый атрибут.
Рассмотрим класс POINT из предшествующей лекции (Текст класса POINT см. в). Исходный текст имеет вид:
class POINT feature
x, y: REAL
... Объявления подпрограмм ...
end
Подпрограммы опущены, так как форма объектов полностью определяется атрибутами соответствующих классов. Данный класс имеет два атрибута x и y типа REAL, следовательно, его экземпляр - это объект с двумя полями, содержащими значения этого типа:


В данной книге объекты - набор полей - изображаются в виде смежных прямоугольников, содержащих соответствующие значения. Внизу курсивом в скобках дается имя класса (в данном случае - POINT). Против каждого поля, тоже курсивом - имена соответствующих атрибутов (x и y). Иногда сверху указывается имя объекта (здесь P_OBJ), не имеющее двойника в программном тексте, но позволяющее ссылаться на объект при обсуждении.
На диаграммах, представляющих структуру ОО-системы или части такой системы, классы изображаются в виде эллипсов. Эти соглашения позволяют не путать классы и объекты.

Простые поля

Оба атрибута класса POINT относятся к типу REAL. Следовательно, соответствующие поля прямого экземпляра POINT содержат действительные числа.
Это пример полей, соответствующих атрибутам одного из "базовых" типов. Формально эти типы определены как классы, а их экземпляры принимают значения из предопределенных диапазонов. К базовым (предопределенным, встроенным)типам относятся:

  • BOOLEAN, может иметь только два различных экземпляра, соответствующих булевым значениям true и false;
  • CHARACTER, экземпляры которого представляют символы;
  • INTEGER, экземпляры которого представляют целые числа;
  • REAL и DOUBLE, экземпляры которых представляют действительные числа одинарной и двойной точности.

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

  • Для типа BOOLEAN два различных экземпляра обозначаются как True и False.
  • Экземпляр CHARACTER будет записываться как символ в апострофах: 'A'.
  • Экземпляр STRING обозначается как последовательность символов в двойных апострофах: "Это строка".
  • Для обозначения экземпляра INTEGER используем обычную десятичную нотацию: 34, -675, +4.
  • Для экземпляров REAL или DOUBLE будет применяться как обычная нотация: 3.5 или -0.05, так и экспоненциальное представление: -5.e-2.

Простое представление книги - класс BOOK
Рассмотрим класс с атрибутами базовых типов:
class BOOK1 feature
title: STRING
date, page_count: INTEGER
end
Типичный экземпляр класса выглядит так:
Поскольку в настоящий момент нас в первую очередь интересует структура объектов, то в последующих примерах все компоненты классов будут атрибутами, а подпрограммы отсутствуют.
Это означает, что на данном этапе обсуждения объекты подобны записям или структурам в языках Pascal и C. Принципиальное отличие от этих языков выражается в том, что, благодаря наличию механизмов скрытия информации, клиенты классов не могут непосредственно присваивать значения полям таких объектов. В Pascal и в C с незначительными синтаксическими различиями допустимо объявление записи с последующим присваиванием (Внимание: Недопустимая нотация! Только для обсуждения.):
b1: BOOK1
...
b1.page_count := 355
Здесь во время выполнения полю page_count объекта, присоединенного к b1, присваивается значение 355. Для классов такая возможность не допускается. Предоставлять клиентам классов разрешение менять поля объектов было бы насмешкой над правилом скрытия информации. В этом случае терял бы смысл выборочный экспорт, управляемый автором класса. В ОО-подходе модификация значений полей допустима только с помощью процедур класса, добавляемых в том случае, если автор класса решит предоставить такую возможность своим клиентам. Далее такая процедура будет добавлена в класс BOOK1.


Разрешение присваиваний вида b1.page_count := 355 в C++ и Java отражает ограничения, возникающие при попытках внедрения объектной технологии в контекст языка C.
Сами разработчики Java отмечают, что программист может испортить объект при наличии общедоступного поля, так как значение такого поля можно изменить путем непосредственного присваивания. Многие авторы языков вводят такую возможность, а затем предупреждают: "не делайте этого". Логичнее определить метод и нотацию, поддерживающие такие ограничения.

В ОО-ПО классы без подпрограмм редко имеют практическое значение. Исключением являются ситуации, когда в родительских классах определяется набор атрибутов, а потомки содержат необходимые подпрограммы. Другим примером могут служить классы, представляющие внешние объекты, которые принципиально невозможно модифицировать, например данные от внешних датчиков в системе реального времени. Но на данном этапе такой подход полезен для понимания основных концепций, подпрограммы будут добавлены позже.
Писатели
Используя указанные выше типы, определим класс WRITER для описания автора книги:
class WRITER feature
name, real_name: STRING
birth_year, death_year: INTEGER
end
Ссылки
Чаще всего нам необходимы объекты с полями, представляющими другие объекты. Например, книга имеет автора, который представлен экземпляром класса WRITER.
Можно ввести понятие подобъекта. В новой версии класса BOOK2 его экземпляры содержат поле, являющееся объектом - экземпляром класса WRITER.
Такое понятие подобъекта, несомненно, полезно, и далее в этой лекции будет показано, как создавать соответствующие классы.
Но это не совсем то, что необходимо. В каждом экземпляре BOOK2 приходится дублировать информацию об одном и том же авторе в виде подобъекта. Причины неприемлемости такого решения:

  • Расходуется дополнительная память. Можно привести в качестве более характерного примера совокупность объектов, представляющих людей. Каждый объект в качестве подобъекта содержит информацию о стране гражданства. Очевидно, что численность населения намного превышает число стран.
  • Более важно, что такая техника не обеспечивает разделения информации. Вполне естественно желание, чтобы внесение изменений в объект WRITER повлекло за собой автоматическое обновление этой информации для всех объектов - книг данного автора.

Лучшим является решение, представленное на. Оно основано на новой версии класса, BOOK3.
Каждый экземпляр BOOK3 в поле author содержит ссылку (reference) на объект типа WRITER. Нетрудно дать точное определение.
Определение: ссылка
Ссылка это значение времени выполнения. Она может быть пустой (void) или присоединенной (attached).
Присоединенная ссылка однозначно идентифицирует объект (присоединена к конкретному объекту).
Наоба поля author экземпляров BOOK3 присоединены к одному экземпляру WRITER. Здесь и далее ссылки, присоединенные к объектам, обозначаются стрелками. На следующем рисунке используется графическое обозначение пустой ссылки, которая может обозначать неизвестного автора.
Определение ссылки не подразумевает конкретной аппаратно-программной реализации. Если ссылка не пуста, то она идентифицирует объект и может рассматриваться как абстрактное имя объекта.
Концепция ссылки должна, безусловно, иметь аналог при реализации. Программирование на уровне машинного кода использует адресацию, многие языки программирования содержат понятие указателя. Понятие ссылки является более абстрактным. Хотя ссылка, в конечном итоге, может быть представлена адресом, не следует из этого исходить. Ссылка может содержать адрес наряду с другой информацией.
Отличие ссылок от указателей выражается в том, что они типизированы. Они напоминают типизированные указатели в Pascal и Ada (но не в C). Это означает, что данная ссылка может быть связана только с объектами определенных типов. По аналогии с обычной жизнью - код города имеет смысл только при наборе телефонных номеров. Он может выглядеть как обычное целое, но никому не придет в голову суммировать коды.
Идентичность объектов
Понятие ссылки приводит к концепции идентичности объектов. Каждый объект, созданный в процессе выполнения ОО-системы, уникален и идентифицируется независимо от значений его полей. Возможны две ситуации:

  • (I1) Два различных объекта могут иметь абсолютно одинаковые поля.
  • (I2) Напротив, поля данного объекта могут изменяться в процессе выполнения системы, но это не влияет на идентификацию объекта.

Эти наблюдения свидетельствуют о неоднозначности высказывания "a обозначает тот же объект, что и b". Можно подразумевать различные объекты с одинаковыми данными (I1) или состояния одного и того же объекта до и после изменения значений полей (I2). Мы будем использовать второе толкование и считать, что значения полей заданного объекта могут изменяться в процессе выполнения, а он остается "тем же самым объектом". В случае (I1) будем говорить о равных (но различных) объектах, точное определение понятия равенства будет дано позже.


В соответствии с определением I2 можно сказать, что поля объекта могут изменяться и это не будет ошибкой. Термин "поле" обозначает одно из значений, составляющих объект, а не соответствующий идентификатор поля - имя одного из атрибутов порождающего класса.
Каждому атрибуту класса соответствует поле объекта (1832 для атрибута date класса BOOK3 на). Атрибуты неизменны в процессе выполнения, как неизменно и деление объекта на поля, а значения полей меняться могут. Любой экземпляр BOOK3 будет всегда содержать четыре поля, соответствующие атрибутам title, date, page_count, author. Значения этих полей могут меняться у каждого экземпляра.

Изучение того, как сделать объекты сохранямыми (persistent), заставит нас продолжить изучение свойств идентичности объектов. (См. "Идентичность объектов",курса "Основы объектно-ориентированного проектирования")

Объявление ссылок

Класс BOOK1 содержал атрибуты только базовых типов, его вариант BOOK3, содержит атрибут, представляющий ссылку на автора.
class BOOK3 feature
title: STRING
date, page_count: INTEGER
author: WRITER -- Новый атрибут.
end
Объявленный тип дополнительного атрибута author это просто имя соответствующего класса: WRITER. Это будет общим правилом: если имеется стандартное объявление класса
class C feature ... end
то объявление некоторой сущности типа C
x: C
обозначает значения, являющиеся ссылками на потенциальные объекты типа C. Такое соглашение, использующее ссылки, обеспечивает большую гибкость и приемлемо в большинстве случаев. Подробное обсуждение этого правила и других возможных решений содержится в последнем разделе данной лекции.
Ссылка на себя
Ничто не препятствует объекту O1 в определенный момент выполнения системы содержать ссылку, присоединенную к самому O1. Такая ссылка на себя может быть косвенной. В ситуации наобъект, имеющий значением поля name: "Almaviva", сам является своим лендлордом (прямая циклическая ссылка). Фигаро любит Сюзанну, которая любит Фигаро (косвенная циклическая ссылка).
Такие циклы в динамических структурах возможны, только если клиентские отношения между соответствующими классами также содержат прямые или косвенные циклы. Объявление класса
class PERSON1 feature
name: STRING
loved_one, landlord: PERSON1
end
содержит прямой цикл (PERSON1 - клиент PERSON1).
Обратное утверждение неверно - присутствие цикла в объявлении класса не означает, что циклы обязательно появятся в структурах времени выполнения. Можно объявить класс
class PERSON2 feature
mother, father: PERSON2
end
Класс является собственным клиентом. Однако если он моделирует соответствующие именам атрибутов отношения между людьми, то структуры времени выполнения никогда не будут содержать циклов, поскольку ни один человек не может быть собственным родителем или предком.
Взгляд на структуру объектов периода выполнения
На основе предшествующего рассмотрения выясняется в первом приближении структура ОО-системы в процессе выполнения.
Система состоит из нескольких объектов с различными полями. Некоторые поля содержат значения базовых типов, а другие являются пустыми или присоединенными ссылками на другие объекты. Каждый объект является экземпляром некоторого типа, основанного на классе (на рисунке тип указывается под объектом). Некоторые типы представлены единственным экземпляром, но гораздо чаще присутствует несколько экземпляров одного типа. На тип TYPE1 представлен двумя экземплярами, остальные - единственным. Некоторые объекты содержат поля только ссылочного типа (экземпляр TYPE4) или только базовых типов (экземпляр TYPE5). Могут присутствовать прямые или косвенные циклические ссылки (верхнее поле экземпляра TYPE2, по часовой стрелке от нижнего экземпляра TYPE1).
Подобная структура может показаться слишком запутанной. Впечатление от приведенной иллюстрации, демонстрирующей различные возможности, можно выразить выражением: "блюдо спагетти".
Это впечатление не совсем правильно. Впечатление простоты должен создавать программный текст, но не структура объектов периода выполнения. Текст отражает определенные отношения (такие как "любит", "имеет хозяина"). Конкретную структуру объектов периода выполнения можно назвать экземпляром таких отношений, она фиксирует связи между элементами данного набора объектов. Моделируемые отношения могут быть простыми, в то время как отношения индивидуумов конкретного множества объектов - достаточно сложными. Понятие "любит" очень просто, однако любовные отношения конкретных людей могут быть безнадежно запутаны.
Во время выполнения могут неизбежно возникать структуры, содержащие много объектов и имеющие запутанную структуру ссылок. Хорошая среда разработки должна предоставлять средства анализа объектных структур для тестирования и отладки.
Сложность динамических структур не должна влиять на статическую картину. Необходимо стараться сохранить набор классов и их отношения настолько простыми, насколько это возможно.
Тот факт, что простым моделям могут соответствовать сложные структуры данных, частично отражает мощь наших компьютеров. Короткий исходный текст может описывать огромные вычисления. Простая ОО-система может порождать в процессе выполнения миллионы объектов, связанных большим числом ссылок. Важнейшей целью программной инженерии является сохранение простоты ПО, даже когда экземпляры объектов такой простотой не обладают.

Объекты как средство моделирования

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

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

Соотношения между этими мирами представлены на.
И на программном и на внешнем уровне (нижняя и верхняя части рисунка) важно разграничить общие понятия и их конкретные реализации (классы и абстрактные отношения слева, объекты и отношения экземпляров справа). Данный момент уже обсуждался в дискуссии о сравнительной роли классов и объектов в предыдущей лекции. Применительно к отношениям необходимо отличать абстрактные отношения loved_one от множества связей loved_one, существующих между элементами конкретного множества объектов.
Это различие невыразимо ни в стандартных математических определениях понятия "отношение", ни в программистской терминологии, например в теории реляционных баз данных. Если ограничиться бинарными отношениями, то и в математике и в теории баз данных отношение определяется как множество пар в форме <x, y>, где x и y являются элементами заданных множеств TX и TY. В терминах программирования все x относятся к типу TX, а все y - к типу TY. Будучи пригодными для математиков, эти определения не подходят для целей моделирования, поскольку не позволяют различать абстрактные отношения и отношения конкретных экземпляров. При моделировании системы отношение "любит" имеет свои общие и абстрактные свойства, совершенно не зависящие от записи того, кто кого любит в конкретной группе людей в некоторый момент времени.


Это обсуждение будет продолжено в, когда будут рассматриваться преобразования между абстрактными и конкретными объектами, и будет дано имя вертикальным стрелкам предыдущего рисунка - функция абстракции. (См. "Функции абстракции",)

Реальность: "седьмая вода на киселе"
Предшествующее обсуждение не содержит ссылок на "реальный мир", - вместо этого используется термин "моделируемая система".
Такое разграничение проводится не всегда. Во многих дискуссиях используется выражение "моделирование реального мира"; аналогичные высказывания содержат и книги по ОО-анализу. Однако говорить о "реальности" применительно к программной системе ошибочно, по крайней мере, по четырем причинам.
Во-первых, реальность отражается в глазах очевидца. Не впадая в профессиональный шовинизм, программист всегда вправе спросить своих заказчиков, почему их системы более реальны, чем его. Возьмите программу, выполняющую математические вычисления - проверку гипотезы четырех красок в теории графов, интегрирование дифференциальных уравнений или решение геометрических проблем на четырехмерной римановой поверхности. Нужно ли нам, программистам, спорить с друзьями (математиками, заказчиками) о том, чьи искусственные объекты - артефакты более реальны - фрагменты программного кода или полное подпространство отрицательной кривизны? (См. также)
Во-вторых, понятие реального мира рушится в нередких ситуациях, когда ПО предназначено для разрешения проблем ПО. Рассмотрим компилятор C, написанный на Pascal. Для него "реальными" объектами являются программы на C. Насколько эти программы более реальны, чем сам компилятор? Это наблюдение применимо и к другим системам, работающим с объектами, существующими только в компьютере. (См.)
Третье соображение обобщает второе. В сегодняшнем информационном мире компьютеры стали частью реальности. На заре появления компьютеров можно было говорить, что создаваемая программная система моделирует реальную систему. Предприятие приобретало компьютеры для автоматизации бизнес процессов. При описании процессов современного банка его ПО является фундаментальной частью банковской системы. Ситуация аналогична квантовой физике, где невозможно отделить измерение от измеряемого механизма. Термин "виртуальная реальность" в какой-то мере отражает данную ситуацию. Программные продукты не менее реальны, чем те, что приходят из внешнего мира. Во всех таких ситуациях программная система пересекается с реальностью, отчего возникает положительная обратная связь, когда работа существующей системы приводит к новым и важным изменениям самой модели, приводя к изменениям программной системы.
Последний довод наиболее фундаментален. Программная система не является моделью реальности. В лучшем случае это модель модели некоторой части некоторой реальности. Система мониторинга пациента больницы не является моделью больницы, но реализацией конкретной точки зрения на некоторые аспекты работы больницы. Это модель модели некоторой части реальности больницы. Астрономическая программа это не модель вселенной, а всего лишь программная модель чьей-то модели некоторых свойств некоторой части вселенной. Финансовая информационная система не является моделью фондового рынка. Это программная реализация модели, разработанной конкретной компанией для описания тех аспектов фондового рынка, которые соответствуют целям данной компании.
Абстрактные типы данных, лежащие в основе ОО-метода, помогают понять, почему не следует придерживаться широко распространенной, но иллюзорной точкой зрения, что мы имеем дело с "реальным миром". Первый шаг к объектной ориентации, выражаемый теорией АТД, состоит в отказе от реальности ради менее грандиозного, но более аппетитного яства, - представляющего множество абстракций, характеризующих операции, доступные клиентам, и их формальные свойства. (На этом построен девиз модельера АТД - не говорите мне, кто вы, скажите, чем вы обладаете.) Мы никогда не претендуем на то, что рассмотрели все возможные операции и свойства: мы выбрали некоторые из них, подходящие для наших целей и отбросили остальные. Моделирование означает отсекание лишнего.
В идеальном случае программная система приходится соответствующей реальности лишь "седьмой водицей на киселе" (cousin twice removed).

Работа с объектами и ссылками

Вернемся к более приземленным проблемам и рассмотрим, как программные системы работают с объектами, как создают и используют гибкие структуры данных.
Динамическое создание и повторное связывание
Что не было показано при описании структуры объектов периода выполнения, так это в высшей степени динамичная природа настоящей ОО-модели. Статическая и ориентированная на стеки политика управления объектами характерна для языков уровня Fortran и Pascal соответственно. Противоположной является политика в настоящем ОО-окружении, позволяющая создавать объекты в период выполнения, когда в них возникает потребность. Какому образцу (типу) соответствуют создаваемые объекты, как правило, невозможно предсказать при статической проверке программного текста.
В начальном состоянии, как описано в предыдущей лекции, создается единственный корневой объект. Затем система повторно выполняет операции создания новых объектов, связывает изначально пустые ссылки с этими объектами, делает ранее присоединенные ссылки пустыми или присоединяет их к другим объектам. Динамическая и непредсказуемая природа этих операций обеспечивает гибкий подход и позволяет поддерживать динамические структуры данных, необходимые для реализации сложных алгоритмов и моделирования быстро меняющихся свойств внешних систем.
Следующий раздел посвящен механизмам, необходимым для создания объектов и манипулирования их полями, в частности, ссылками.

Инструкция создания
Рассмотрим создание экземпляра класса BOOK3. Это возможно только с помощью подпрограммы класса, являющегося клиентом BOOK3, как, например:
class QUOTATION feature
   source: BOOK3
   page: INTEGER
   make_book is
         -- Создание объекта BOOK3 и присоединение его к source.
      do
         ... См. ниже ...
      end
end
Этот класс описывает цитирование книги в других публикациях. Он содержит два поля: ссылку на цитируемую книгу и число страниц, содержащих ссылки на нее.
Механизм создания экземпляра QUOTATION (скоро он будет рассмотрен) предусматривает инициализацию всех его полей. Правило инициализации по умолчанию определяет, что любое ссылочное поле (в данном примере - поле, соответствующее атрибуту source) после инициализации должно содержать пустую ссылку. Другими словами, создание объекта типа QUOTATION не сопровождается созданием объекта типа BOOK3.
Ссылка остается пустой, пока над ней не будут выполнены некоторые действия, - таково общее правило. Изменить значение ссылки можно, создав, например, новый объект. В процедуре make_book это делается следующим образом:
make_book is
      -- Создание объекта BOOK3 и присоединение его к source.
   do
      create source
   end
Это иллюстрация простейшей формы инструкции создания: create x , где x - атрибут охватывающего (enclosing) класса или, как будет показано позже, локальная сущность охватывающей подпрограммы. Далее эта базовая нотация будет расширена.
Сущность x, именованная в инструкции (в данном примере source), называется целью (target) инструкции создания.
Данная форма известна как "базовая инструкция создания". Другая форма, включающая вызов процедуры класса, скоро появится. Вот точное определение действия базовой инструкции создания:
Результат базовой инструкции создания
Эффект инструкции создания вида create x , где тип цели x является ссылочным типом, основанном на классе C, состоит в выполнение трех следующих действий:

  • (C1) Создание нового экземпляра C(набора полей, по одному на каждый атрибут C). Пусть OC - это новый экземпляр.
  • (C2) Инициализация каждого поля OC соответствующими стандартными значениями по умолчанию.
  • (C3) Присоединение значения x (ссылки) к OC.

На этапе C1 создается экземпляр C. На этапе C2 устанавливаются предопределенные значения всех полей, зависящие от типа соответствующего атрибута:
Значения по умолчанию при инициализации
Для ссылок значение по умолчанию - пустая ссылка.
Для полей BOOLEAN значение по умолчанию - False.
Для полей CHARACTER значение по умолчанию - символ null.
Для чисел (типов INTEGER, REAL или DOUBLE) значение по умолчанию - ноль в соответствующем данному типу представлении.
Итак, для цели source типа BOOK3 в соответствии с объявлением класса
class BOOK3 feature
title: STRING
date, page_count: INTEGER
author: WRITER
end
результатом инструкции создания create source, выполняемой при вызове процедуры make_book класса QUOTATION, будет объект изображенный на.
После инициализации значения целочисленных полей равны нулю. Ссылочное поле author и поле title типа STRING, содержат пустые ссылки. Тип STRING, о котором ничего не говорится в правилах инициализации, двойственен, - фактически являясь ссылочным типом, он рассматривается во многих ситуациях как базовый тип.

Общая картина

Важно проследить за последовательностью происходящих событий. Для рассмотренного выше экземпляра BOOK3 происходит следующее:

  • (B1) Создан экземпляр QUOTATION. Пусть Q_OBJ - этот экземпляр и имеется сущность a, значение которой ссылка, присоединенная к Q_OBJ.
  • (B2) Спустя некоторое время после B1 вызов вида a.make_book приводит к выполнению процедуры make_book с Q_OBJ в качестве цели.

Правомерен вопрос - как будет создан сам Q_OBJ (шаг B1)? Это, оставляя проблему, отодвигает ее вглубь. Но к этому моменту мы уже знаем ответ на этот вопрос: все возвращается к первопричине - Большому Взрыву. Для выполнения системы необходимо снабдить ее корневым классом и процедурой этого класса, названной процедурой создания. В начале выполнения автоматически создается один объект - корневой объект - экземпляр корневого класса. Корневой объект является единственным объектом, не создаваемым инструкциями программного текста; он приходит извне, как objectus ex machine (объект от машины). Начав с одного, провидением посланного объекта, далее уже программа может создавать объекты нормальным путем через подпрограммы, выполняющие инструкции создания. Первой выполняемой подпрограммой является процедура создания, автоматически применяемая к корневому объекту. Не всегда, но чаще всего она содержит по крайней мере одну инструкцию создания, что в предыдущей лекции называлось началом грандиозного фейерверка, процесса, создающего столько новых объектов, сколько нужно текущему выполнению.
Для чего необходимо явное создание объектов?
Объекты создаются явным образом. Объявление сущности
b: BOOK3
не влечет за собой создание объекта во время выполнения, это происходит, когда некий элемент системы выполнит операцию
create b
Это может показаться удивительным. Разве объявления b недостаточно для создания объекта? Что хорошего в объявлении, если объект не создается?
Достаточно минуты размышления для понимания того, что разделение объявления и создания объекта является единственно разумным решением.
Первый аргумент - reductio ad absurdum (доведение до абсурда). Предположим, что начата обработка объявления и немедленно создается соответствующий объект. Но это экземпляр класса BOOK3, имеющий атрибут author ссылочного типа WRITER, значит поле author - ссылка, для которой опять нужно создавать объект. Этот объект вновь содержит ссылочные поля, требуется опять делать то же самое и начинается длинный путь рекурсивного создания объектов.
Этот аргумент еще более убедителен для таких классов как PERSON1, содержащих ссылки на себя:
class PERSON1 feature
name: STRING
loved_one, landlord: PERSON1
end
Появление каждого экземпляра PERSON1 повлечет за собой создание двух других таких объектов (соответствующих loved_one и landlord ) и начнется бесконечный цикл. Такие прямые или косвенные циклические ссылки не экзотика - они часто встречаются и необходимы.
Другой аргумент следует из обсуждения роли объектной технологии как мощного метода моделирования. Если для каждого ссылочного поля будет создаваться новый объект, то не было бы возможности выделить пустые ссылки и множественные ссылки на один и тот же объект. И то, и другое необходимо для реалистичного моделирования систем:

  • В некоторых случаях требуется, чтобы ссылка не была связана ни с каким объектом. Примером может служить пустая ссылка author для обозначения неизвестного автора.
  • В других случаях, в соответствии с моделью две ссылки должны быть присоединены к одному объекту. В примере с циклическими ссылками присутствовали поля loved_one двух персон PERSON1, присоединенные к одному и тому же объекту. Не имело бы смысла создание своего объекта для каждого из этих полей. Все, что требуется, - это операция присваивания (рассмотрена далее в этой лекции) для присоединения ссылки к уже существующему объекту. В еще большей степени это соображение применимо для ссылки на себя (поле landlord верхнего объекта в том же примере).

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


В дискуссии о наследовании будет показано, что инструкция создания может использовать синтаксис create {T}x для создания объекта, чей тип T является наследником типа объявленного для x.

Процедуры создания

Все до сих пор рассмотренные инструкции создания основывались на инициализации по умолчанию. В некоторых случаях инициализация, определенная в языке, может нас не устраивать - хотелось бы обеспечить создаваемый объект специфической информацией. В этом предназначение процедур создания.
Перекрытие инициализации по умолчанию
Для использования инициализации, отличной от предопределенной умолчанием, необходимо класс снабдить одной или несколькими процедурами создания. Такие процедуры должны быть перечислены в предложении, начинающимся ключевым словом creation в начале класса перед первым предложением feature. Схема такова:
indexing
...
class C creation
p1, p2, ...
feature
... Объявления компонент, включая реализацию процедур p1, p2, ...
end


Совет, отражающий стиль: в случае класса с единственной процедурой создания - для нее рекомендуется имя make. Для классов с двумя и более процедурами создания желателен префикс make_, за которым следует квалификатор, как в следующем примере POINT. (См. "Правильный выбор имен",курса "Основы объектно-ориентированного проектирования")

Соответствующая инструкция создания в этих случаях имеет другую форму:
create x.p (...)
где p одна из процедур создания перечисленных в разделе creation, и в круглых скобках (...) перечисляются фактические аргументы p. Результатом является создание объекта с использованием значений по умолчанию, как и ранее, а затем вызов p с заданными аргументами. Такая инструкция является комбинацией инструкции создания и вызова процедуры и называется порождающим вызовом (creation call). (Оригинальная версия класса POINT приведена в
В качестве примера добавим две процедуры создания в класс POINT, что позволит клиентам при создании новой точки указывать ее начальные координаты - декартовы или полярные. Введем процедуры создания: make_cartesian и make_polar. Вот схема:
class POINT1 creation
make_cartesian, make_polar
feature
... Компоненты из предыдущей версии класса:
x, y, ro, theta, translate, scale, ...
feature {NONE} - Этот вариант экспорта рассмотрен ниже.
make_cartesian (a, b: REAL) is
-- Инициализация точки с декартовыми координатами a и b.
do
x := a; y := b
end
make_ polar (r, t: REAL) is
-- Инициализация точки с полярными координатами r и t.
do
x := r * cos (t); y := r * sin (t)
end
end
Для такого класса клиент будет создавать точки инструкциями вида:
create my_point.make_cartesian (0, 1)
create my_point.make_polar (1, Pi/2)
В обоих случаях создается точка с одинаковыми координатами в предположении, что константа Pi имеет общепринятый смысл. Вот правило, определяющее эффект порождающего вызова. Первые три пункта правила такие же, как и для базисной формы, приведенной ранее:

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика