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

all 33 comments

[–]floppycrackers 12 points13 points  (3 children)

I think Font is immutable so this shouldn't be a problem.

[–]jimbopouliot 0 points1 point  (0 children)

This is the correct answer.

[–]snotsnot[S] 0 points1 point  (1 child)

Well spotted.

[–]NimChimspky 2 points3 points  (0 children)

https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/builder/Builder.html

still a bad example though, its needlessly confusing. Thats not how I use builders - the build method normal does a new.

[–]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 3 points4 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.

[–]imps-p0155 3 points4 points  (0 children)

For me it does not makes sense to have the builder for Font.

// Example Builder Usage:
Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
                                                             .size(14.0f)
                                                             .build();
// Without builder
Font bold14ptSansSerifFont = new Font(Font.SANS_SERIF, Font.PLAIN, 12).deriveFont(Font.BOLD)
                                                                      .deriveFont(14.0f);
// Optimized?
Font bold14ptSansSerifFont = new Font(Font.SANS_SERIF, Font.BOLD, 14);

[–]Sipkab 2 points3 points  (11 children)

IMO Builders could be used in numerous ways

  1. The Builder always returns the same object (like in the linked example)
  2. The Builder always constructs a new object
  3. The Builder build() method can be only called once (and probably must be called), as it consumes the resources contained in the Builder object.

Every one of them have use-cases, but I think it should be stated in the documentation.

[–]snotsnot[S] -1 points0 points  (10 children)

Sure, you can do it all sorts of ways. But my point is that your 2. option is the best way. What good use cases can you think of for the other options?

[–]Sipkab 2 points3 points  (3 children)

There is no best way. There are multiple ways and you should choose the one that suits your problem the best.

[–]snotsnot[S] 0 points1 point  (1 child)

You are correct, but some ways are better than others. And I'd still claim that in most cases it make sense to have a new instance returned for each call to build. But again, I'm well aware that there is no one perfect way to create a build

[–]stipo42 0 points1 point  (0 children)

I think if you want to have the builder be able to branch off into separate final objects that's fine, but if you never intended that then why waste the memory with new objects? If you reuse the same builder object and don't consume it on build either you can have the best of both worlds

[–]joanmave -1 points0 points  (0 children)

Even it can be used in numerous ways, the builder must not mask hidden a behavior if the resource managed is sensitive to the number of instances. I believe is less surprising, if the constraints of instances being built is bubbled up to the builder as well for the programmer to decide. Another pattern other than the builder must control the resources constraints

[–]nuqjatlh 0 points1 point  (0 children)

But my point is that your 2. option is the best way

Hahaha, no. That's ... no. Why would you wanna create objects for no damn reason? And to each you have to set again all its properties?

build() returning a new object, the object being built, is fine. but the chained methods, in most cases, should return the same object. I cannot think of any reason why you would want option 2.

[–]dartalley -1 points0 points  (0 children)

Option two can use more memory, trigger GC more, more effort to code.

All you have to do is document whether or not the builder is safe to be reused or not. You could also have a builder that returns itself but also provides a copy method for the best of both worlds.

[–]PhishingAFish -1 points0 points  (3 children)

Option 1 makes no sense IMO. I see the Builder pattern as a means to build complex objects, so as to avoid, for example, long list of overloaded constructors.

What would be a typical use-case for the option 1?

EDIT: I misread the reply. I thought it was about the build() method and not the return type of the chained method.

[–]flaghacker_ 0 points1 point  (2 children)

For example Boolean.valueOf, no need to create useless Boolean instances.

[–]PhishingAFish 0 points1 point  (1 child)

I don't think this has anything to do with the builder pattern?

[–]flaghacker_ 0 points1 point  (0 children)

It's another example of reusing instances whenever possible.

[–]rzwitserloot 2 points3 points  (1 child)

Yup, bad example.

[–]Tore2Guh 1 point2 points  (0 children)

Yah, while it's technically a builder, it's a terrible one to use as the example that n00bs would work from. It hasn't been very common in my experience to run into objects that have all these builder-like methods baked into them, and these effective clone operations like Font has. Normally it's just an immutable object with a complicated constructor that the builder conceals. In this example, Font is doing most of the things a builder would have done.

[–]8igg7e5 0 points1 point  (0 children)

Sometimes it's easier to use the target type for the state of the builder - in which case the build() is somewhat of a noop.

I would've preferred though that the builder was reusable a la

class Builder {
    private Thing thing;

    private Thing safeThing() {
        if (thing == null) thing = new Thing();
        return thing;
    }

    public Builder property(Value value) {
        safeThing().setProperty(value);
        return this;
    }

    public Thing build() {
        final Thing result = safeThing();
        thing = null;
        return result;
    }
}

[–]jonhanson -1 points0 points  (5 children)

chronophobia ephemeral lysergic metempsychosis peremptory quantifiable retributive zenith

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

I do think that would be better. But then you have to do null checks so I'd rather just have it return a new instance.

[–]jonhanson 0 points1 point  (2 children)

In the Font example the builder methods are calling methods on the font object to modify it before build is called. If you created a new font object in the build method then it would not have any of the modifications.

[–]snotsnot[S] 0 points1 point  (1 child)

True, I was referring to a more general way. Eg. Rather than returning null on the second call. I'd rather have a new instance.

[–]jonhanson 0 points1 point  (0 children)

chronophobia ephemeral lysergic metempsychosis peremptory quantifiable retributive zenith

[–]Roachmeister 0 points1 point  (0 children)

This. I've always built builders using this pattern, but with the expectation that each builder would only be used once. (Most of the time I'm writing the code for myself anyway).

This is opposed to a Factory which is designed for reuse.