Инкапсуляция
Объект сам управляет своим состоянием
У объекта есть поля, но это не означает, что любой код должен иметь возможность менять их как угодно. Если внутреннее состояние доступно напрямую, внешний код может легко записать значение, после которого объект окажется в некорректном состоянии.
Инкапсуляция помогает провести границу: детали хранения данных остаются внутри класса, а внешний код работает с объектом через разрешённые операции. Так класс сам контролирует, какие изменения допустимы.
Закрываем поля с помощью private
Модификатор private делает член класса доступным только внутри этого класса.
Поэтому поля, которые описывают внутреннее состояние объекта, обычно закрывают от прямого доступа.
class Thermostat {
private int temperature = 20;
public int getTemperature() {
return temperature;
}
public void increase() {
if (temperature < 30) {
temperature++;
}
}
public void decrease() {
if (temperature > 10) {
temperature--;
}
}
}
Здесь температура хранится в закрытом поле. Внешний код не может написать
thermostat.temperature = 100 и обойти правила класса.
Он может только вызвать публичные методы, а они не позволяют температуре выйти за диапазон от 10 до 30.
public — это разрешённый вход в объект
Модификатор public используют для операций,
которые класс намеренно предоставляет внешнему коду.
В примере выше getTemperature(),
increase() и decrease()
образуют публичный способ работы с термостатом.
Главная польза здесь не в том, что поле «спрятано», а в том, что класс сохраняет контроль над своим состоянием. Если позже правило изменения температуры поменяется, внешний код сможет продолжить вызывать те же методы, а проверку можно будет изменить внутри класса.
Геттеры и сеттеры — не цель инкапсуляции
Частая ошибка — сделать все поля private,
а затем добавить к каждому обычный геттер и сеттер без каких-либо правил.
Формально прямой доступ исчезнет, но внешний код всё равно сможет присвоить полю практически любое значение.
Поэтому не каждому полю обязательно нужен сеттер.
Иногда лучше предоставить операции, которые отражают смысл объекта:
например, increase() и decrease()
вместо setTemperature(int temperature).
Так по коду сразу видно, что с объектом разрешено делать.
private помогает закрыть детали,
а публичные методы задают безопасный способ работы с ними.