Доступ клиентов к атрибутам

Доступ клиентов к атрибутам

Экспорт атрибута с использованием рассмотренной техники делает его доступным клиентам только для чтения в виде my_point.x. Модификация атрибута путем присваивания не разрешается. Следующая синтаксическая конструкция недопустима для атрибутов (Внимание: недопустимая конструкция - только для иллюстрации.):

my_point.x := 3.7

Действует простое правило. Если attrib является атрибутом, то a.attrib является выражением, а не сущностью. Следовательно, ему нельзя присвоить значение, как нельзя присвоить значение выражению a + b.

Возможность модификации attrib достигается добавлением экспортируемой процедуры вида:

set_attrib (v: G) is

-- Установка значения attrib равным v.

do

attrib := v

end

Вместо этого можно было бы представить следующий синтаксис для разграничения прав доступа пользователей (Внимание: не поддерживаемая нотация. Только для обсуждения.)

class C feature [AM]

...

feature [A]{D, E}

...

здесь A обозначает возможность чтения, а M - модификации. Это устранило бы потребность в частом написании процедур аналогичных set_attrib.

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

class COUNTING feature

counter: INTEGER

increment is

-- Увеличение значения счетчика

do

counter := counter + 1

end

decrement is

-- Уменьшение значения счетчика

do

counter := counter - 1

end

end

Аналогичным образом клиенты класса POINT не имеют возможности непосредственно изменять координаты точки x и y. Для этой цели служат экспортированные процедуры translate и scale.

При изучении утверждений мы рассмотрим еще одну принципиальную причину недопустимости непосредственных присваиваний a.attrib := some_value. Причина в том что не любые значения some_value могут быть допустимыми. Можно определить процедуру

set_polygon_size (new_size: INTEGER) is

-- Установить новое значение числа вершин многоугольника

require

new_size >= 3

do

size := new_size

end

параметр которой может равен 3 или больше. Прямое присваивание не позволяет учесть это условие и в результате получается некорректный объект.

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

Рис. 7.8.  Возможные варианты прав доступа клиентов к атрибутам

Уровень 0 соответствует полному отсутствию доступа к атрибуту. На уровне 1 открыт доступ только для чтения. На уровне 2 разрешена модификация с помощью специальных алгоритмов. На уровне 3 новое значение может быть присвоено, только если удовлетворяет определенным условиям, как в примере для многоугольника. На уровне 4 ограничения снимаются.

Решение, описанное в данной лекции, следует из приведенного анализа. Экспорт атрибута дает клиентам право доступа только для чтения (уровень 1). Разрешение на модификацию обеспечивается написанием и экспортом соответствующих процедур. Они предоставляют ограниченные права, как в примере для счетчика (уровень 2), право модификации при соблюдении определенных условий (3) и неограниченный доступ (4).

Это решение является развитием идей, существующих в различных ОО-языках:

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

[x]. C++ и Java представляют другую крайность. Если атрибут экспортирован, то он сразу становится доступным на уровне 4 для чтения и для записи путем прямого присваивания в стиле my_point.x := 3.7. Единственный путь реализации других уровней это полное скрытие атрибута и написание экспортированных процедур для поддержки уровней 2 и 4 и функций для уровня 1. Далее все аналогично Smalltalk. Поддержка уровня 3 невозможна в связи с отсутствием в этих языках механизма утверждений.

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