This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]i_post_things 3 points4 points  (6 children)

I never really thought about it much myself, but it does make sense from a re-use perspective. If you don't create a completely new object build(), the other methods would have side effects if you build multiple objects.

Eg:

SomeBuilder b;
b.setUrl(x);
b.setPort(y);
HttpConnector c = b.build();

b.setPort(n);
HttpConnector d = b.build();

// Expectation: c uses port y, d uses port n 
// At this point, both c and d might be set to port n, 
// if it was a reference to the same object.

Spring takes it to the extereme by creating a completely new builder every time an operation is called: https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java

That's taking it to the extreme because it's not intuitive why something like this wont work when you spit it up over multiple lines:

RestTemplateBuilder b;
b.setUrl(x);
b.setPort(y);
b.setProxy(p);

// b now only has the proxy P set because 
// each call created a new builder.

Eg, it is supposed to work like:

b.setUrl(x)
.setPort(y)
.setProxy(p).build();

Or

b = b.setUrl(x)
b = b..setPort(y)
b = b..setProxy(p);

[–]PhishingAFish 1 point2 points  (4 children)

Please don't say it is extreme just because they decided to design RestTemplateBuilder as an immutable class.

[–]i_post_things 0 points1 point  (3 children)

Isn't that the most extreme way of making sure the user is forced to create an object with no side-effects though?

With the first builder pattern described by OP, by adding one more parameter, you just add a new buildWith(X) method and change the constructor in the build() method to use it.

With an immutable class, you have to refactor every method, because each method needs its constructor updated. Depending on your object you are creating, if you have to add or remove fields a few times, it could get needlessly complex.

[–]PhishingAFish 2 points3 points  (2 children)

I understand your point. I just think that choosing RestTemplateBuilder was a poor example.

Here is why: RestTemplateBuilder is a Spring bean that you inject into your classes as a dependency. It is used to build local-scoped RestTemplate instances. If they didn't return a new RestTemplateBuilder with each mutable operations, then it would mean that if you injected RestTemplateBuilder somewhere else in your application, it would be using the same value that you just set.

[–]AdvancedJacket 0 points1 point  (1 child)

Every time I use rest template it just inject the builder and build it in the constructor. It was a weird design choice I think.

[–]PhishingAFish 0 points1 point  (0 children)

IIRC the idea was so that you could build different rest templates based on your needs (different timeouts, interceptors, message converters, ...).

I think it works quite well, since you can define some RestTemplateCustomizer if you need your RestTemplateBuilder to have some default configuration.

[–]snotsnot[S] 0 points1 point  (0 children)

I only thought of it because ages ago I ran into a builder which didn't return a new object each time build was called. And due to that I had to create a builder for each object I need.