Читаем Основы объектно-ориентированного программирования полностью

Пусть мы хотим определить константу - комплексное число i, действительная часть которого равна 0, а мнимая 1. Первое, что приходит в голову, - это буквальная константа вида

i: COMPLEX is "Выражение, определяющее комплексное число (0, 1)"

Как записать выражение после is? Для пользовательских типов данных никакой формы записи неименованных констант не существует.

Можно представить себе вариант нотации на основе атрибутов класса:

i: COMPLEX is COMPLEX (0, 1)

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

Кроме того, как гарантировать соответствие неименованной константы инварианту класса, если таковой имеется?

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

<p>Однократные функции</p>

Пусть константный объект - это функция. Например, i можно (в иллюстративных целях) описать внутри самого класса COMPLEX как

i: COMPLEX is

-- Комплексное число, re= 0, а im= 1

do

create Result.make_cartesian (0, 1)

end

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

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

i: COMPLEX is

-- Комплексное число, re= 0, im= 1

once

create Result.make_cartesian (0, 1)

end

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

Результат, найденный при первом вызове однократной функции, может использоваться во всех экземплярах класса, включая экземпляры потомков, где эта функция не переопределена. Переопределение однократных функций как обычных (и обычных как однократных) допускается без всяких ограничений. Так, если COMPLEX1, порожденный от класса COMPLEX, заново определяет i, то обращение к i в экземпляре COMPLEX1 означает вызов переопределенного варианта, а обращение к i в экземпляре самого COMPLEX или его потомка, отличного от COMPLEX1, означает вызов однократной функции, то есть значения, найденного ею при первом вызове.

<p>Применение однократных подпрограмм</p>

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

<p>Разделяемые объекты</p>

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

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

Пример такого объекта - окно вывода информации об ошибках. Пусть все компоненты интерактивной системы могут направлять в это окно свои сообщения:

Message_window.put_text ("Соответствующее сообщение об ошибке")

где Message_window имеет тип WINDOW, чей класс описан следующим образом:

class WINDOW

creation

make

feature

make (...) is

Перейти на страницу:

Похожие книги

«Ага!» и его секреты
«Ага!» и его секреты

Вы бы не хотели, скажем, изобрести что-то или открыть новый физический закон, а то и сочинить поэму или написать концерт для фортепьяно с оркестром?Не плохо бы, верно? Только как это сделать? Говорят, Шиллер уверял, будто сочинять стихи ему помогает запах гнилых яблок. И потому, принимаясь за работу, всегда клал их в ящик письменного стола. А физик Гельмгольц поступал иначе. Разложив все мысленно по полочкам, он дожидался вечера и медленно поднимался на гору лесной дорогой. Во время такой прогулки приходило нужное решение.Словом, сколько умов, столько способов заставить мозг работать творчески. А нет ли каких-то строго научных правил? Одинаковы ли они для математиков, биологов, инженеров, поэтов, художников? Да и существуют ли такие приемы, или каждый должен полагаться на свои природные способности и капризы вдохновения?Это тем более важно знать, что теперь появились «электронные ньютоны» — машины, специальность которых делать открытия. Но их еще нужно учить.Решающее слово здесь принадлежит биологам: именно они должны давать рецепты инженерам. А биологи и сами знают о том, как мы думаем, далеко не все. Им предстоит еще активнее исследовать лабораторию нашего мышления.О том, как ведутся эти исследования, как постепенно «умнеют» машины, как они учатся и как их учат, — словом, о новой науке эвристике рассказывает эта книга.

Елена Викторовна Сапарина

Зарубежная компьютерная, околокомпьютерная литература