Книга: Основы объектно-ориентированного программирования

Селективный экспорт и скрытие информации

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

Рассмотрим способы скрытия компонент от всех или некоторых клиентов. Данный раздел содержит лишь введение в нотацию - подробному рассмотрению интерфейсов классов посвящена одна из последующих лекций (лекция 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 нет принципиальной разницы, однако во втором случае исходный текст становится более понятным и удобочитаемым. Именно такой стиль объявления скрытых компонент будет использоваться далее в этой книге.

"Внутренний" экспорт

Рассмотрим объявление класса

indexing
замечание: "Ошибочное объявление (объяснение см. ниже)"
class S6 feature
x: S6
my_routine is do ... print (x.secret) ... end
feature {NONE}
secret: INTEGER
end -- class S6

Наличие в объявлении класса атрибута x типа S6 и вызова x.secret делает его собственным клиентом. Но такой вызов недопустим, так как компонент secret скрыт от всех клиентов! Тот факт, что неавторизованным клиентом является сам класс S6, нечего не меняет - объявленный статус secret делает недопустимым любой вызов вида x.secret. Всякие исключения нарушают простоту сформулированного правила.

Есть простое решение: написать вместо feature {NONE} предложение feature {S6} , экспортируя компоненту самому себе и своим потомкам.

Необходимо отметить, что подобный прием необходим, только если в тексте класса присутствует квалифицированный вызов аналогичный print (x.secret). Очевидно, что неквалифицированный вызов secret в инструкции print (secret) допустим без дополнительных ухищрений. Все компоненты, объявленные в данном классе, могут использоваться в подпрограммах данного класса и его потомков. Только при наличии квалифицированных вызовов приходится экспортировать компонент самому себе.

Оглавление книги


Генерация: 0.359. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз