#28 Модификаторы доступа элементов класса: public, private, protected. Инкапсуляция
Primary tabs
Модификаторы доступа
Для элементов класса во многих языках существуют три уровня доступности:
- public -- публичные (общедоступные элементы) элементы, напр. только с такими элементами мы имели дело в примерах первого урока по ООП.
Публичные элементы доступны как изнутри методов класса так и из внешнего кода (т.е. такого кода, который не относится к методам класса).
- protected - т.н. "защищенные" элементы, к ним можно обращаться из методов класса и из методов его потомков (т.е. из методов классов унаследованных от данного), но нельзя из внешнего кода
- private -- "приватные/закрытые", доступ к ним может быть только из собственных методов класса, но ни классы-потомки ни внешний код, не имеют доступа к этим элементам.
Далее рассмотрим использование этих модификторов на примерах.
ПРИМАЧЕНИЕ: в примерах далее мы будем использовать для protected и private т.н. строгие версии: strict protected и strict private. Это связано с тем, что в отличие от ряда других языков Паскаль "закрывает" доступ без "strict" не на уровне класса , а на уровне модуля (файла, т.е. без strict доступ даже для внешнего кода в том же файле будет открыт), но т.к. все наши примеры располагаются в одом файле, то мы используем дополнительное слово "strict", чтобы закрыть доступ даже на уровне одного файла.
В других языках используются точно такие же модификаторы, работающие подобным же образом, но ключевое слово "strict" не требуется.
Инкапсуляция
Инукапсуляция - это "сокрытие внутри", т.е. некий прием позволяющих сделать сделать скрытыми некие части системы от внешего на наблюдателя
Далее мы будем рассматривать способы сокрытия элементов класса от другого кода.
Пример №1 - private: доступ для кода класса
Рассмотрим пример кода:
type Cat = class // родительский класс public name: string; // поле name constructor create(nameValue: string); procedure sayHello(); end; constructor Cat.create(nameValue: string); begin self.name := nameValue; end; procedure Cat.sayHello(); begin writeln('Привет, я ' + self.name + '!'); end; var CatItem: Cat; begin CatItem := Cat.create('Мурка'); CatItem.name := 'Мурка22'; // можем заменить имя снаружи CatItem.sayHello(); end.
-- здесь поле name может быть изменено во внешнем, коде, как это и показано в теле программы.
Давай закроем доступ к полю name для внешенего кода, сделать это можно перенеся поле name в секцию private:
type Cat = class // родительский класс public // секция публичных элементов constructor create(nameValue: string); procedure sayHello(); strict private // секция закрытых элементов name: string; // приватное поле end; constructor Cat.create(nameValue: string); begin self.name := nameValue; end; procedure Cat.sayHello(); begin writeln('Привет, я ' + self.name + '!'); end; var CatItem: Cat; begin CatItem := Cat.create('Мурка'); // CatItem.name := 'Мурка22'; // не сработает! CatItem.sayHello(); end.
-- если расскомментировать строку с попыткой замены значения поля во внешнем коде дела программы, то компилятор Паскаля бросит ошибку.
Пример №2 - protected для защищенных полей. Доступ только классу и наследникам
Если мы хотим дать доступ к какому-либо элементу класса только методам этого класса и еще и классам-наследникам (но при этом не давать доступ коду из других областей видимости), то мы можем использовать секцию protected, рассмотрим пример:
type Cat = class // родительский класс public constructor create(nameValue: string); procedure sayHello(); strict protected name: string; end; Tiger = class(Cat) // класс-потомок procedure roar(); // метод рычания end; constructor Cat.create(nameValue: string); begin self.name := nameValue; end; procedure Cat.sayHello(); begin writeln('Привет, я ' + self.name + '!'); end; procedure Tiger.roar(); begin writeln(self.name + ': rrrrrrrrrr!'); end; var CatItem: Cat; TigerItem: Tiger; begin CatItem := Cat.create('Мурка'); CatItem.sayHello(); TigerItem := Tiger.create('Шархан'); TigerItem.sayHello(); TigerItem.roar(); // TigerItem.name = '123'; // не сработает для защищенного поля! end.
Принцип минимальных необходимых прав
Когда вы выбираете какой именно доступ дать для метода или поля класса, руководствуйтесь популярным и в других областях принципом минимальных необходимых прав:
прав должно быть ровно столько, сколько необходимо для работы
--т.е.:
- если какие-то элементы не должны использоваться наследниками или еще более отдаленным кодом - используйте private
- если же наследникам нужен доступ -то protected.
- Если же доступ к элементу необходим и из внешнего кода - тогда единственный вариант это объявлять его в открытой секции public
Решения конфликта имен с помощью модификаторов доступа
Ранее в уроке по ООП мы говорили о возможном конфликте имен между публичным полем класса и аргументами его методов, теперь когда мы разбираемся в модификаторах доступа, при желании можно глубже вникнуть в эту проблему и изучить другие варианты ее решения.
Видео-материалы
- Инкапсуляция, private, модификаторы доступа - разбор кода: https://youtu.be/fxA1Ns7SPrI
- Модификатор protected и наследование классов - разбор кода: https://youtu.be/S7tliDtRlRE
Задачи для самостоятельного решения
-
Есть код:
type Cat = class // родительский класс public constructor create(nameValue: string); procedure sayHello(); function getName(): string; strict protected name: string; end; Tiger = class(Cat) public function getRoarStart(): string; // вернет строку для начала рыка рыка procedure roar(); // само рычание end; constructor Cat.create(nameValue: string); begin self.name := nameValue; end; procedure Cat.sayHello(); begin writeln('Привет, я ' + self.getName() + '!'); end; function Cat.getName(): string; begin result := self.name; end; function Tiger.getRoarStart(): string; begin result := self.getName() + ':'; end; procedure Tiger.roar(); begin writeln(self.getRoarStart() + ' rrrrrrrrrr!'); end; var CatItem: Cat; TigerItem: Tiger; begin CatItem := Cat.create('Мурка'); CatItem.sayHello(); TigerItem := Tiger.create('Шархан'); TigerItem.sayHello(); TigerItem.roar(); // рычит end.
-- для двух элементов классов здесь применена избыточная область видимости, измените модификаторы доступа для этих элементов так, чтобы видимость их была минимальной достаточной для работы программы.
- Log in to post comments
- 1472 reads
vedro-compota
Sat, 03/04/2023 - 16:48
Permalink
type
type
Cat = class // родительский класс
public
constructor create(nameValue: string);
procedure sayHello();
strict protected
name: string;
end;
Tiger = class(Cat) // класс-потомок
procedure roar();
end;
constructor Cat.create(nameValue: string);
begin
self.name := nameValue;
end;
procedure Cat.sayHello();
begin
writeln('Привет, я ' + self.name + '!');
end;
procedure Tiger.roar();
begin
writeln(self.name + ': rrrrrrrrrr!');
end;
var
CatItem: Cat;
TigerItem: Tiger;
begin
CatItem := Cat.create('Мурка');
CatItem.sayHello();
TigerItem := Tiger.create('Шархан');
TigerItem.sayHello();
TigerItem.roar();
// TigerItem.name = '123'; // не сработает для защищенного поля!
end.
_____________
матфак вгу и остальная классика =)