Как проектировать классы в Java
Что проверяют
Понимаете ли вы, что класс это граница ответственности и инвариантов, а не набор полей с геттерами. Следом обычно просят спроектировать конкретный класс или спрашивают, когда вы выберете наследование вместо композиции.
Как отвечать
Идите от поведения, а не от полей: что объект умеет и какие правила гарантирует. Дальше опорные решения:
- инварианты в конструкторе: объект нельзя создать невалидным. Проверки через
Objects.requireNonNullи явные исключения, а не надежда на вызывающий код; - неизменяемость по умолчанию: поля
private final, без сеттеров. Для носителей данных с Java 16 естьrecord, он сам даётequals,hashCodeиtoString; - инкапсуляция это не геттеры: вместо
setBalance()методwithdraw(amount), который сам проверяет остаток. Коллекции наружу отдаются черезList.copyOfили неизменяемые представления; - композиция вместо наследования: наследование оставьте для настоящего «является», остальное закрывайте через
finalилиsealed(Java 17); - зависимости через конструктор: класс получает интерфейс, а не создаёт реализацию через
new. Так его легко тестировать и собирать в Spring; - контракт
equalsиhashCode: переопределяются только вместе, иначе объект потеряется вHashMap; - SOLID как проверка: у класса одна причина меняться, клиенты не зависят от методов, которые им не нужны.
Сильный ход: взять пример вроде Order и показать, как из анемичной модели с сеттерами получается класс, который не даст перевести заказ из «отменён» в «оплачен».
Где спотыкаются
Генерируют геттер и сеттер на каждое поле и называют это инкапсуляцией. Формально поля приватные, по сути наружу открыто всё.
Строят глубокие иерархии ради переиспользования пары методов. Правка базового класса потом ломает наследников в неожиданных местах.
Перечисляют паттерны списком и первым называют Singleton. В современных проектах жизненным циклом объектов управляет контейнер Spring, а ручной синглтон со статикой мешает тестам.