определяет f как атрибут-константу (constant attribute), значение которой равно some_value. (Атрибуты-константы обсуждаются в лекции 18)

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

Атрибуты или функции?

Рассмотрим подробнее следствия принципа унифицированного доступа и объединения атрибутов и подпрограмм под общим заголовком - компоненты. (См.'Унифицированный доступ', лекция 3. См. также данную лекцию.)

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

Рассмотрим класс PERSON, содержащий компонент типа INTEGER без параметров. Если автор клиентского класса записывает выражение

Isabelle.age

то единственно важным будет то, что age возвращает целое число - значение возраста экземпляра PERSON, который во время выполнения присоединен к сущности Isabelle. Компонент age может быть как атрибутом, так и функцией, вычисляющей результат, используя значение атрибута birth_date и текущую дату. Автору клиентского класса нет необходимости знать, какое из этих решений выбрал автор PERSON.

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

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

Решение рассматривать атрибуты и функции без параметров как эквивалентные для клиентов имеет два важных следствия, рассматриваемые подробно в последующих лекциях:

[x]. Первое следствие касается программной документации. Стандартная документация класса для клиента, известная как краткая форма класса, составляется так, чтобы отсутствовала разница в описаниях атрибутов и функций без параметров. (См. 'Использование утверждений в документации: краткая форма класса', лекция 11)

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

Экспорт атрибутов

В завершение предшествующей дискуссии необходимо обсудить вопрос об экспорте атрибутов. Рассмотренный в этой лекции класс POINT имеет атрибуты x и y и экспортирует их клиентам, также как и функции rho и theta. Для получения значения атрибута некоторого объекта используется обычная нотация для вызова компонентов в виде my_point.x или my_point.theta.

Эта возможность экспорта атрибутов отличается от соглашений, принятых во многих ОО-языках. Типичным примером является Smalltalk, в котором только подпрограммы (методы) могут быть экспортированы классом, а прямой доступ к атрибутам (свойствам) запрещен.

Следуя подходу Smalltalk, доступ к атрибуту можно обеспечить только с помощью небольшой экспортированной функции, возвращающей значение атрибута. В примере класса POINT назовем атрибуты internal_x, internal_y и добавим функции abscissa и ordinate. Лаконичный синтаксис Smalltalk допускает присваивание одинаковых имен атрибуту и функции, избавляя от необходимости придумывать специальные имена для атрибутов.

class POINT feature

-- Общедоступные компоненты:

abscissa: REAL is

-- Горизонтальная координата

do Result := internal_x end

ordinate: REAL is

-- Вертикальная координата

do Result := internal_y end

... Другие компоненты аналогичны предыдущей версии ...

feature {NONE}

-- Компоненты недоступные клиентам:

internal_x, internal_y: REAL

end

Этот подход имеет два недостатка:

[x]. Он побуждает авторов классов писать много маленьких функций, аналогичных abscissa и ordinate. Несмотря на то, что такие функции будут очень короткими, автор класса будет тратить на их написание дополнительные усилия, а их присутствие затрудняет восприятие исходного текста.

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

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

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату