В чём преимущество использования сеттеров (setter methods) вместо прямого доступа к полям класса?

«В чём преимущество использования сеттеров (setter methods) вместо прямого доступа к полям класса?» — вопрос из категории ООП, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Сеттеры (и геттеры) являются частью принципа инкапсуляции в ООП. Их основная цель — контролировать доступ к внутреннему состоянию объекта, скрывая реализацию.

Прямой доступ к полю (проблема):

public class Account {
    public double balance; // Публичное поле
}

// Клиентский код может сделать что угодно:
Account acc = new Account();
acc.balance = -1000; // Некорректное состояние! Никакой проверки.

Контролируемый доступ через сеттер (решение):

public class Account {
    private double balance;

    public void setBalance(double amount) {
        if (amount < 0) {
            throw new IllegalArgumentException("Balance cannot be negative");
        }
        this.balance = amount;
        // Дополнительная логика при изменении
        log.info("Balance updated to: " + amount);
        notifyObservers(); // Например, для паттерна Наблюдатель
    }
}

Ключевые преимущества сеттеров:

  1. Валидация: Гарантия корректности данных перед их установкой.
  2. Гибкость и поддержка: Можно изменить внутреннее представление данных (например, хранить баланс в центах), не ломая API класса.

    private long balanceCents; // Теперь храним в центах
    
    public void setBalance(double amount) {
        this.balanceCents = (long) (amount * 100); // Конвертация
    }
  3. Добавление побочной логики: Логирование, уведомления, кэширование, ленивая инициализация.
  4. Совместимость: Интеграция с фреймворками, которые полагаются на соглашение JavaBeans (например, Spring DI, JPA, библиотеки для сериализации).

Когда можно обойтись без сеттеров? В неизменяемых (immutable) объектах, где состояние задаётся только через конструктор.