Builders or constructors? We reason out loud

Hello! I want to speculate about the advisability of using builders for simple objects.



For simplicity, I will use the annotations lombok'a:



@Value

@Builder



After a little googling, we get that builder - Separates the construction of a complex object from its presentation so that as a result of the same construction process, different views can be obtained. Is it only for complex objects?



Let's look at a simple example:



@Value
public class Info {
    @Nullable String uuid;
    @Nullable String email;
    @Nullable String phone;
}


Quite a simple class. In fact, we get an immutable object that is initialized through the constructor.



But, as we can see, all fields are nullable, and creating such objects will not look very nice:



        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);
...


There are certainly options:



  1. Objects with a few fields of different types can be delivered with several constructors. But that doesn't solve the problem of the class above.
  2. Using setters is subjective, it clutters up the code.




What about the builder?



@Value
@Builder
public class Info {
    @Nullable String uuid;
    @Nullable String email;
    @Nullable String phone;
}


We get a very elegant construction of a simple object:



        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();
...
}


However, to use jackson in the project, it is necessary to add our class so that it deserializes successfully:



@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 {

    }
}


We get our pros and cons for both approaches:



builder:



+

1. The code becomes more concise.

3. null in constructor parameters is not conspicuous.

2. Less chance of confusing parameters of the same type.

-

1. We create an extra object that the GC as a whole will safely remove, but you shouldn't forget about it.

2. If necessary, use jackson - pile up the class.



constructor:



+

1. Minimally piles up our class, no water.

2. No unnecessary objects creation.

-

1. Very often null will arrive in the constructor of such an object.

2. It is possible to make a mistake when someone changes the code.



Outcome



Based on my experience, I tend to use builders. The cost is not high, but the output is a code that is pleasant to read.



And of course, write tests to avoid the 2nd negative point of using constructors.



PS This is my first article, I will be grateful for constructive criticism and comments.



All Articles