Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование лекции.doc
Скачиваний:
49
Добавлен:
12.11.2019
Размер:
5.53 Mб
Скачать

9.2. Принцип инкапсуляции

Создаваемые программистом объекты могут включаться в библиотеки и использоваться не только им лично, но и многими другими разработчиками программ. Следовательно, нужно предусмотреть какую-то защиту от неверного использования свойств и методов. С другой стороны, как мы уже видели, прямое изменение значений свойств объекта – операция крайне нежелательная (изменили модуль зуба, а диаметр пересчитать забыли). Эти два соображения привели к появлению принципа инкапсуляции, гласящего: значения свойств не должны меняться напрямую, а только через вызовы соответствующих методов. Рассмотрим два примера программного кода:

Без инкапсуляции

С инкапсуляцией

TYPE TA=СLASS a:WORD;

….

VAR c:TA; BEGIN c:=TA.Create; c.a:=10

TYPE TA=CLASS

a:WORD; PROCEDURE SetA(w:WORD);

….

VAR c:TA; BEGIN c:=TA.Create; c.SetA(10)

В первом случае значение свойства а можно менять напрямую, просто написав с.а:=10. Это явное нарушение принципа инкапсуляции. Во втором случае для изменения значения свойства а введен специальный метод SetA. Внутри этого метода при необходимости будут пересчитываться значения других свойств, зависящих от значения свойства а. Кроме того, можно выполнять проверку корректности присеваемого свойству значения. Если речь идет о свойстве "число зубьев зубчатого колеса", то это число не может быть меньше шести (что, кстати, отражено в самом слове "шестеренка"), иначе не получится плавного зацепления.

Таким образом, инкапсуляция нужна по следующим соображениям:

  1. Изменение значения одного из свойств часто должно приводить к изменению значения другого свойства.

  2. Возможна проверка корректности присваиваемых свойству значений.

Однако ввести метод для присваивания значения свойству еще недостаточно. Ничего же не запрещает горе-программисту не использовать этот метод и по-прежнему писать с.а:=10, что разрушит все наши построения. Поэтому для полного соблюдения принципа инкапсуляции имеется возможность создания скрытых свойств, которые нельзя будет менять напрямую, а только через вызовы методов:

TYPE TA=CLASS PRIVATE a:REAL; PUBLIC b:REAL END;

Перед списком скрытых свойств ставится слово PRIVATE, а перед списком открытых для изменения свойств – слово PUBLIC. В приведенном фрагменте свойство а является скрытым и попытка выполнить оператор вида с.а:=10 приведет к ошибке "Field identifier expected". Однако внутри методов все скрытые свойства видны по-прежнему. Рекомендуется делать скрытыми все свойства объекта

9.3. Поля и свойства

Итак, принцип инкапсуляции требует, чтобы любая работа со свойствами объекта происходила только через вызовы его методов. Следовательно, если у объекта obj есть свойство n:byte и его надо изменить, следующая строка:

obj.n:=10

некорректна. По идее, надо вызывать метод:

obj.SetN(10)

Однако первый вариант записи (с явным использованием оператора присваивания) гораздо легче воспринимается.

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

Рис. 9.20. Поля и свойства.

Иначе говоря, для того, чтобы можно было считывать или изменять значения полей, в соответствие полю ставится свойство объекта (property). Свойство объекта доступно извне объекта. При его изменении или считывании его значения происходит автоматический вызов метода - процедуры или функции, связанной с этим свойством. Таким образом, любые изменения значений полей происходят не напрямую, а только через вызов процедуры/функции.

На Рис. 9 .20 представлена схема объекта, имеющего три поля fld1, fld2, fld3. Из них поле fld2 является полностью скрытым – с ним не связано никакое свойство. Данное поле можно использовать только внутри методов объекта, но извне оно не будет доступно. С полями же fld1, fld3 cвязаны свойства prop1и prop3 соответственно. Обычно тип данных свойств совпадает с типом данных связанных с ними полей. Для записи значения в поля предназначены методы SetFld1(n:byte) и SetFld3(n:word). На вход им подаются новые значения свойств. Чтение значений свойств осуществляется методами-функциями GetFld1:byte и GetFld3:word. Описание объекта будет иметь вид:

TYPE TO=CLASS

PRIVATE

fld1:byte;

fld2:string;

fld3:word;

PROCEDURE SetFld1(n:byte);

PROCEDURE SetFld3(n:byte);

FUNCTION GetFld1:byte;

FUNCTION GetFld1:word;

PUBLIC

PROPERTY prop1:byte READ GetFld1 WRITE SetFld1;

PROPERTY prop3:byte READ GetFld3 WRITE SetFld3;

END;

Описание PROPERTY создает свойство объекта и назначает методы для его чтения (READ) и записи (WRITE). Свойство может не иметь метода для записи – тогда оно будет доступно только для чтения, или не иметь метода для чтения – тогда в него можно будет только записывать значения.