Для упрощения буду использовать аннотации lombok'a:
@Value
@Builder
Недолго погуглив, получаем, что builder Отделяет конструирование сложного объекта от его представления так, что в результате одного и того же процесса конструирования могут получаться разные представления. Только ли для сложных объектов?
Рассмотрим на простом примере:
@Valuepublic class Info { @Nullable String uuid; @Nullable String email; @Nullable String phone;}
Довольно таки простой класс. На деле получаем иммутабельный объект, который инициализируется через конструктор.
Но, как мы видим, все поля nullable, и создание такие объектов будет выглядеть не очень красиво:
final Info info1 = new Info(null, "email@email.com", "79998888888"); final Info info2 = new Info("3d107928-d225-11ea-87d0-0242ac130003", null, null); final Info info3 = new Info("3d107928-d225-11ea-87d0-0242ac130003 ", "email@email.com", null);...
Безусловно, есть варианты:
- Объекты, где немного полей разных типов, можно завезти несколько конструкторов. Но это не решает проблему класса выше.
- Использовать setter'ы субьективно, нагромождает код.
А что с билдером?
@Value@Builderpublic class Info { @Nullable String uuid; @Nullable String email; @Nullable String phone;}
Мы получаем весьма элегантное построение не сложного объекта:
final Info info1 = Info.builder() .uuid("3d107928-d225-11ea-87d0-0242ac130003") .phone("79998888888") .build(); final Info2 info2 = Info.builder() .email("email@email.com") .phone("79998888888") .build();...}
Однако, для использование в проекте jackson'а, необходимо дополнить наш клас, чтобы он успешно десериализовывался:
@Value@Builder(builderClassName = "InfoBuilder")@JsonDeserialize(builder = Info.InfoBuilder.class)public class Info { @Nullable String uuid; @Nullable String email; @Nullable String phone; @JsonPOJOBuilder(withPrefix = "") public static class InfoBuilder { }}
Получаем свои плюсы и минусы за оба подхода:
builder:
+
1. Код становится лаконичнее.
3. null в параметрах контруктора не бросается в глаза.
2. Меньше шанс перепутать параметры одного типа.
-
1. Создаем лишний объект, который GC в целом благополучно уберет, но забывать об этом не стоит.
2. При необходимости использовать jacson нагромоздим класс.
конструктор:
+
1. Минимально нагромождает наш класс, никакой воды.
2. Нет создания лишних объектов.
-
1. Весьма часто в конструктор такого объекта будет прилетать null.
2. Есть вероятность ошибится, когда кто-то будет вносить изменения в код.
Итог
Опираясь на свой опыт склоняюсь к использованию билдеров. Плата за это не высока, а на выходе имеем код, который приятно читать.
И конечно же, пишите тесты, чтобы избежать 2-го отрицательного пункта использования контрукторов.
P.S. Это моя первая статья, буду благодарен конструктивной критике и комментариям.