Записи, пожалуй, самая обсуждаемая фича, появившаяся в Java 14. В то же время вызывает много критики из-за их необъектно-ориентированного характера. Типичный аргумент гласит, что записи — это концепция процедурного программирования, и ей нет места в объектно-ориентированном языке.
Действительно ли записи поощряют процедурное, а не объектное мышление?
Ну да и нет. Я полностью согласен с тем, что записи не являются объектно-ориентированной функцией, с другой стороны, я считаю, что для них есть допустимые варианты использования даже в идеально объектно-ориентированных приложениях.
Причина в том, что нет настоящих объектов на границах. Рассмотрим, например, ресурс REST, объект базы данных или свойства конфигурации. Это всего лишь структуры данных, но они должны быть представлены в коде Java.
Эволюция рекордов
Конечно, у нас есть типы структур данных, такие как Map
или Set
в Java, и их достаточно для многих случаев. Однако иногда полезно иметь типизированную структуру данных — например, для декларативной проверки, маршалинга или отображения. Традиционно Объекты передачи данных (DTO) используются в таких сценариях:
class AccountData { private String username; private String password; private String email; public AccountData( String username, String password, String email) { this.username = username; this.password = password; this.email = email; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } AccountData that = (AccountData) o; return username.equals(that.username) && password.equals(that.password) && email.equals(that.email); } @Override public int hashCode() { return Objects.hash( username, password, email); } }
Ну, это действительно много стандартного кода для такой простой вещи. Его можно ненавидеть, можно любить, но Ломбок довольно элегантно восполняет именно этот пробел:
@Data class AccountData { private String username; private String password; private String email; }
Lombok основан на манипуляциях с кодом, которые можно рассматривать как неадекватную «черную магию», которую многие разработчики не хотят иметь в своих кодовых базах. Java 14 решает эту проблему с помощью записей:
record AccountData ( String username, String password, String email) {}
Любое сходство с классами данных Kotlin чисто случайно:
data class AccountData ( var username: String, var password: String, var email: String)
Проблема с DTO
Итак, в чем здесь проблема? Записи Java, похоже, представляют DTO как языковую функцию. В чем проблема с DTO? "О" есть. Объекты передачи данных вообще не являются объектами! DTO — это просто типизированная структура данных.
Код должен быть как можно более явным, а структуры данных не должны называться объектами. Это заблуждение приводит к плохому проектированию объектов, обычно к печально известной анемичной модели предметной области.
С другой стороны, у записей (и даже у ломбокской аннотации @Data
) нет объекта в имени. Записи делают это явным: данные рассматриваются как данные.
Вывод
Записи Java — это новая функция, которая добавляет в язык дополнительный тип структуры данных. В отличие от DTO, записи делают структуры данных в коде явными. Это правильные инструменты для правильных целей. При неправильном использовании они становятся злыми слугами, как и все остальное.
Я не думаю, что записи могут вызвать какой-либо сдвиг мышления от объектно-ориентированного дизайна к процедурному, потому что хороший объектно-ориентированный дизайн не рассматривает DTO как объекты, и записи не могут этого изменить. Простота использования сравнима с Lombok, но без магии; это означает, что искушение использовать записи не должно быть больше. Поскольку анемичное моделирование с DTO никогда не было хорошим объектно-ориентированным дизайном, я считаю, что записи не сделают его намного хуже.
В Java есть гораздо более опасные общие практики, такие как нулевые ссылки, статические методы и глобальные константы, но это совсем другая история…
Первоначально опубликовано в моем блоге.