Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лр Основные понятия ООП.docx
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
41.6 Кб
Скачать

Об инкапсуляции

Инкапсуляция означает сокрытие деталей реализации класса. Класс разделяется на две части: внутреннюю и внешнюю. Внешняя часть (интерфейс) тщательно продумывается исходя из того, каким образом могут взаимодействовать с объектами данного класса другие объекты программы. Внутренняя часть закрыта от посторонних, она нужна только самому классу для обеспечения правильной работы открытых методов.

Например, в классе Dog есть целочисленное поле age (возраст). Можно оставить его открытым, тогда его при необходимости можно будет изменить простым присваиванием (очень удобно). Но при этом ничто не мешает присвоить этому полю заведомо некорректное значение (например, 666 или -5 или 3000). Это может произойти из-за ошибки в программе. Или, к примеру, пользователь вводит возраст собаки в текстовое поле, а программа присваивает его в ответ на нажатие кнопки (и пользователь может ошибиться). Это нежелательный случай. Лучше сделать поле age закрытым (private) и добавить два открытых метода: getAge() и setAge(). Первый метод будет просто возвращать значение скрытого поля:

public int getAge() {

return age;

}

Второй метод позволит задать новый возраст собаки, производя при этом проверку присваиваемого значения.

public void setAge (int newAge) {

if (newAge < 0) System.out.println("Как это понимать? Собака еще не родилась?");

else if (newAge > 30) System.out.println("Они столько не живут");

else age = newAge;

}

Теперь мы видим, что возраст можно изменить, лишь вызвав метод setAge(), который в случае неподходящего параметра выведет в консоль сообщение и не будет ничего изменять.

Профессиональные программисты, разрабатывающие программы по объектно-ориентированной методологии, скрывают все поля своих классов, создавая для каждого из них открытые методы c приставками get и set, причем в методах set проводятся все необходимые проверки.

Заметим напоследок, что в нашем примере неправильный возраст может «прорваться» через конструктор при создании нового объекта. Никто ведь не мешает написать:

Dog dog1 = new Dog("Тузик", 2000);

Для того, чтобы этого не случилось, необходимо переписать конструктор:

public Dog(String n, int a) {

name = n;

age = setAge(a);

}

Теперь проверка осуществляется в конструкторе. Попытка завести в программе собаку с явно некорректными данными не увенчается успехом. Если возраст будет меньше 0 или больше 30, присваивание не выполнится и атрибут age будет иметь значение по умолчанию (для типа int это 0). Такая вот маленькая собачка...

Упражнение

Наш класс Dog содержит принципиальную ошибку. Он имеет скрытое поле name, которому можно присвоить начальное значение во время создания объекта, но нельзя изменить и даже узнать впоследствии. Напишите методы getName() и setName(). Никаких проверок проводить не нужно.

Перегрузка

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

Например, в дополнение к конструктору, который уже есть в классе Dog, мы можем описать конструктор без параметров:

public Dog() {

name = "Незнакомец";

}

В этом конструкторе объекту класса Dog (очевидно, собака с неизвестной кличкой) присваивается при регистрации в программе имя «Незнакомец». Теперь мы можем воспользоваться одним из двух конструкторов:

Dog dog1 = new Dog("Тузик", 2); // Собака по кличке Тузик, возраст 2 года

Dog dog2 = new Dog(); // Собака по кличке «Незнакомец», возраст 0

Dog dog3 = new Dog(10); // Неверно! Не существует конструктора с такими параметрами

Нельзя создавать несколько одноименных методов с одинаковым числом и типом параметров.

Упражнение

Добавьте в класс Dog третий конструктор для случаев, когда известен возраст, но неизвестная кличка собаки так, чтобы третья команда в примере имела смысл.

Полиморфизм

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

Изменить работу любого из методов, унаследованных от класса-предка, класс-потомок может, описав новый метод с точно таким же именем и параметрами. Это называется переопределением. При вызове такого метода для объекта класса-потомка будет выполнена новая реализация.

Пусть, к примеру, мы хотим расширить наш класс Dog классом BigDog, для того, чтобы наша программа особым образом моделировала поведение больших злых собак. В частности, большие собаки лают по-другому. Во-первых, громче, а во-вторых, они не умеют считать. Поэтому мы переопределим метод voice():

class BigDog extends Dog {

public void voice() {

for (int i = 1; i <= 30; i++) {

System.out.print("ГАВ-");

}

}

}

Теперь создадим в методе main() двух разных собак: обычную и большую и заставим их лаять.

Dog dog = new Dog("Тузик", 2);

dog.voice();

BigDog bigdog = new BigDog();

bigdog.voice();

Объект подкласса всегда будет одновременно являться объектом любого из своих суперклассов. Поэтому в том же примере мы могли бы обойтись и одной переменной:

Dog dog = new Dog("Тузик", 2);

dog.voice();

dog = new BigDog();

dog.voice();