Операции, не входящие в число "стандартных", называют свободными операциями. Приведем два примера свободных операций.
[x]. Далее в классе ARRAY будет использован инфиксный компонент-операция "@" для функции, возвращающей указанный элемент массива. Обращение к i-ому элементу массива будет выглядеть как a @ i.
[x]. В класс POINT вместо функции distance можно ввести компонент-операцию "|-|" и расстояние между точками p1 and p2 будет записываться в виде p1 |-| p2, а не как p1.distance(p2).
Все операции имеют фиксированный приоритет, стандартные операции имеют свой обычный приоритет, а все свободные операции обладают более высоким приоритетом.
Использование компонентов-операций позволяет использовать общепринятую нотацию для выражений и одновременно отвечает требованиям полной унификации системы типов. Реализация арифметических и булевых операций как компонентов класса INTEGER вовсе не должна быть причиной снижения производительности. Концептуально a + x является вызовом компонента, но хороший компилятор может создать в результате обработки такого вызова код не менее эффективный, чем компиляторы C, Pascal, Ada или других языков, в которых "+" это жестко зафиксированная языковая конструкция.
В большинстве случаев мы можем забыть о том, что использование операций в выражениях фактически является вызовом процедур, поскольку конечный эффект будет таким же, как и при традиционном подходе. В то же время приятно сознавать, что и в этом случае не допущено отхода от принципов ОО-подхода.
Селективный экспорт и скрытие информации
До сих пор все компоненты класса были доступны всем потенциальным клиентам. Это, безусловно, не всегда приемлемо, поскольку скрытие информации является важным элементом построения последовательной и гибкой архитектуры.
Рассмотрим способы скрытия компонент от всех или некоторых клиентов. Данный раздел содержит лишь введение в нотацию - подробному рассмотрению интерфейсов классов посвящена одна из последующих лекций (лекция 5 курса "Основы объектно-ориентированного проектирования"). В примерах для простоты будут рассматриваться только именованные компоненты, однако все изложенные ниже соображения справедливы и для компонент-операций.
Неограниченный доступ
По умолчанию все компоненты доступны для всех клиентов. Для класса
class S1 feature
f ...
g ...
...
end
компоненты f, g, ... доступны всем клиентам S1. Это означает, что если в классе C объявлена сущность x класса S1, то вызов
x.f ...
является допустимым, если выполнены все другие условия корректности вызова f.
Ограничение доступа клиентам
Для ограничения доступа клиентов к некоторой компоненте h, будет использована возможность включения в объявление класса двух или более разделов feature. Объявление будет выглядеть следующим образом
class S2 feature
f ...
g ...
feature {A, B}
h ...
...
end
Компоненты f и g по-прежнему доступны всем клиентам. Компонент h доступен только для классов A и B, а также их потомков (прямых или косвенных). Это означает, что для некоторого x типа S2 следующий вызов
x.h
является допустимым только в исходных текстах классов A, B или одного из их потомков.
В особом случае, когда необходимо скрыть компонент i от всех клиентов, можно объявить его экспортируемым пустому списку клиентов (Не рекомендуемый стиль (см. ниже S5).):
class S3 feature { }
i ...
end
В этом случае любой вызов x.i(...) недопустим. Единственная возможность обращения к i - неквалифицированный вызов
i (...)
в тексте подпрограммы класса S3 или его потомков. Такой механизм обеспечивает полное скрытие информации.
Возможность полного скрытия компонента от клиентов доступна во многих ОО-языках, а вот механизм селективного ограничения доступа, проиллюстрированный на примере h, к сожалению, практически не поддерживается. Подобный более тонкий контроль доступа необходим достаточно часто. Вопрос о важности селективного экспорта обсуждается в дискуссии в конце лекции.
В примерах последующих лекций мы столкнемся с различными примерами селективного экспорта и рассмотрим его методологическую роль при разработке интерфейсов.
Стиль объявления скрытых компонент
Использованный выше стиль объявления скрытой компоненты i не слишком удачен. Это хорошо видно в следующем примере (Не рекомендуемый стиль (см. ниже S5).)
class S4 feature
exported ...
feature {}
secret ...
end
где secret является скрытой компонентой, а exported - общедоступной. Разница в написании feature {} с пустым списком в скобках и feature без всяких скобок едва заметна. Гораздо разумнее вместо пустого использовать список, содержащий единственный класс NONE (Рекомендуемый стиль.)
class S5 feature
... exported ...
feature {NONE}
... secret ...
end
Класс NONE является базовым библиотечным классом и обсуждается далее в связи с наследованием. По определению он не может иметь потомков и нельзя создать его экземпляр. Таким образом, компонент, экспортированный классу NONE, фактически является скрытым. Между объявлениями S4 и S5 нет принципиальной разницы, однако во втором случае исходный текст становится более понятным и удобочитаемым. Именно такой стиль объявления скрытых компонент будет использоваться далее в этой книге.