Let's say I have a class Dot
with a builder:
public class Dot {
private final Double x;
private final Double y;
private final Color color;
private Dot(Double x, Double y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public static Builder createBuilder() {
return new Builder();
}
public Double getX() { return x; }
public Double getY() { return y; }
public Color getColor() { return color; }
public Builder getBuilder() {
return new Builder().setX(x).setY(y).setColor(color);
}
public static class Builder {
private Double x;
private Double y;
private Color color;
public Builder setX(Double x) {
this.x = x;
return this;
}
public Builder setY(Double y) {
this.y = y;
return this;
}
public Builder setColor(Color color) {
this.color = color;
return this;
}
public Dot build() {
return new Dot(x, y, color);
}
}
}
Now I see two possible ways one could instantiate the builder. Through its constructor:
new Dot.Builder().setX(...
or through a factory method:
Dot.createBuilder().setX(...
(In the latter case I would make the Builder
's constructor private
.)
Factory methods (or factories) are (to my knowledge) useful when the actual type of the returned value might change later on. This is something that is probably not going to occur with a builder.
My best argument for using a factory method would be: Say that the builder uses a final field String id
that has to be set in its constructor, but certain restrictions apply to what constitutes an ID. Throwing an exception on an illegal id string should not be done in a constructor. Therefore a factory method would be better.
However I feel like I missed some more important arguments. Does a best practice for this case exist? What other arguments exist for/against using a factory method here?
Best Answer
Builder
is a class internal toDot
. For me this tells me thatBuilder
is strongly coupled withDot
and thatBuilder
is a utility ofDot
for some objective, in this case object construction.This is objectively one step away from
Builder
being an internal class hidden away from the caller entirely. The only link you, the caller, should have toBuilder
should be throughDot
as a general rule. And although there's nothing stopping you from makingBuilder
's constructor public and accessing it directly, I confirmly believe it is an antipattern.Therefore, you should have a static factory method in
Dot
that returns an instance ofBuilder
. You mention that it isn't likely that you'd ever need to extendBuilder
, and that's all fine and good, but when you're given a more flexible option with no drawbacks while you're developing, you grab hold of it like your life depended on it. Should you ever need to extendBuilder
, you could makeBuilder<T>
an interface and create a customizedDotBuilder<Dot>
which implements it which when called creates an instance ofDot
.I'm usually against constructors performing work that might likely throw exceptions. It's one thing to throw an exception in a constructor for an invalid parameter or for a very unlikely situation such as Xml implementation not existing, and quite another to attempt to establish a database connection which can and will fail quite easily. If you did need to do work in your
Builder
constructor, you could do so lazily putting it off until the actual creation of the object as to not make your constructor explode. Though if I've gotBuilder
class pegged correctly, it isn't the type of class that should ever explode upon creation. If that isn't your case, give serious thought to making it work in the way that one might expect it to work (aka possible exceptions when callingbuild()
method only).Also if I may add, having a builder class
Builder
with many of the same methods asDot
is not probably a good idea. Your situation may be different and this may be the simplified version, so if this doesn't apply to you, ignore this advice. Though it is my opinion thatBuilder
is largely unnecessary here.Dot
can returnthis
after each setter and perform precisely the same functionality. Give it some thought.