nanovche / expense-tracker

Rest api with spring boot; follows youtube tutorial
0 stars 0 forks source link

Use Builder pattern instead of adding properties via the constructor #1

Open velizartodorov opened 3 years ago

velizartodorov commented 3 years ago

https://github.com/nanovche/expense-tracker/blob/62d3f2e5dc3c7f51fe5f968d5518da08cef777ae/expense-tracker-api/src/main/java/com/pairlearning/expensetracker/domain/Category.java#L11

For now, you have a few properties in this class and adding them through the constructor is not a problem. But imagine if the client requirements change, and you have 20 - your constructor will become an absolute nightmare to instantiate and initialize. Use Builder pattern instead. Same thing goes for Transaction and User classes.

nanovche commented 3 years ago

So basically I need to use builder whenever the class implementation is subject to change? Does this include classes that are not part of the public API? If I am sure that class will stay as is forever a normal constr will do? Here I have used all-args-constr in the builder since all the fields are required. If requirements need more fields - setters can be easily added for those.

velizartodorov commented 3 years ago

So basically I need to use builder whenever the class implementation is subject to change? Does this include classes that are not part of the public API?

Builder pattern is used, when a composite object needs to be built (having multiple properties). Compare these two examples:

Category(String property1, String property2, String property3, String property4, String property5, String property6, String property7, String property8)

category.builder()
              .property1(smth)
              .property2(smth) 
              .property3(smth)
              ...
              build();

Which is easier to read? Imagine the following madness as well:

Category("String1", null "String2", null, null, "String3") etc.

Builder prevents this nightmare of null params.

Both for API and internal use it's a good practice, since you and your teammates will be also consumer of your own code.

If I am sure that class will stay as is forever a normal constr will do?

Yep, but being sure about that it's hardly never the case. :)

Here I have used all-args-constr in the builder since all the fields are required. If requirements need more fields - setters can be easily added for those.

I'd use all-args-constr if the properties are no more than 3, as Bob Martin suggests. If I have to set all fields at once, setting through Builder pattern is a better approach. If the states of the object require different properties at different places in the project itself, I'd go for the setters approach only.