Last of an object, that can be fairly complex in some cases, from the class of the object itself thus the builder can deliver different types of objects based on how the building process progresses. This is a clear example of the separation of concerns.
Immutable objects are objects that are created and can not be altered after the creation process.
Builders and immutable objects just come together very natural.
The builder and the built objects are very closely related and therefore they are usually put into the same package. But why are they implemented in separate classes? On one hand: they have to be separate classes of course. That is the whole thing is about. But on the other hand: why can not the builder be an inner class of the built class? Builder usually collect the building information in their own state and when the caller requests the object to be built this information is used to build the built object. This “use” is a copy operation most of the time. If the builder is inner class all this information can be stored in the built object. Note that the inner class can access all private parts of the class embedding it. The builder can create a built object just not ready yet and store the build information in it. When requested to build all it does are the final paintings.
This pattern is followed by Guava for the immutable collections. The builders are static inner classes. If you look at the code of ImmutableList you can see that there is an internal
Builder class inside the abstract class.
But this is not the only way to embed the builder and the implementation. What if we embed the implementation inside the builder? The builder is the only code that needs mutable access to the class. An interface defining the query methods the class implements should be enough for anybody else. And if we get to this point why not to create a matrjoschka?
Lets have an interface. Lets have a builder inside the interface as an inner class (static and public by default and can not be any other way). Lets have the implementation inside the builder as a private static class implementing the outer interface.
public interface Knight { boolean saysNi(); public class Builder { private Implementation implementation = new Implementation(); public Builder setState(String say) { implementation.say = say; return this; } public Implementation build() { Implementation knight = implementation; implementation = null; return knight; } private static class Implementation implements Knight { private String say; public boolean saysNi() { return say.indexOf("ni") != -1; } } } }
The builder can access any fields of the Knight implementation since they are in the same top level class. (JLS1.7, section 6.6.1 Determining Accessibility)
There is no other way (except nasty reflection tricks or byte code abuse, which are out of scope for now) to get access to the implementation except using the builder.
The builder can be used to build the implementation and once it returned it it has no access to it anymore, there is no way to modify the implementation via the builder. If the implementation is immutable it is guaranteed to save the state.
Is this a pattern or an antipattern?
Technically, this is bad code, since the build() method has a return and side-effects. People expect that when they run build(), they can run it again immediately and get another copy of the same thing (or the same copy, if you implement caching – which, by the way, would be kind of a pain to add into your design). Or, they want to make small changes to the current build for the next build, but don’t want to have to redo the entire build order. Yours requires doing a whole new build order (which, in this case is fine, since there’s only one field in the Implementation, but most objects contain more than that).
I would declare this an anti-pattern.
I accept your point. This structure does not support structures like
a = builder.x().y().z();
b = a.build();
c = a.build();
to get two different copies of a built object. It is like creating a building. You build up the floors and at the end you finish with the roof. You just can not say: let’s have another roof and we get a new building.
Even though the embedded builder pattern can be formulated the way to support the more functional style you suggest. All it needs to store all the values in the builder and then execute all the building process when built is called. That would supports your point and that is still the same pattern. Small difference, a bit more complex.
Fluent api builder go even farther returning a new copy of the builder after each build method invocation so you can branch a new build process after each and every floor build in the house. However I believe that is not the point for the fluent api and for the builder pattern. The aimed use is to start a build process, call all builder methods and then build in one chained method call to get one object. If you need a similar object you just call the builder methods again to make the code readable. It may be counterintuitive when you really have numerous builder methods, but then it is a smell that the built object is bloated.
As for the caching note: I feel that implementing cache into the pattern would be the violation of single responsibility.
Anyway: thanks for your opinion. After all these blogs are exactly for that.
I can see most of your points, but it still has the problem that your build method is a mutator and accessor in one, which is a cardinal sin.
As for caching, Effective Java recommends it for Immutable objects, if you expect that users will be makong multiple copies of the same object. All of the objects for java primitives do it.
I was thinking long time why I don’t fell agreeable with your statements. I do embrace the idea of single responsibility and after the night sleep I realized that this principle is called “single responsibility” and not single action principle. The reason for that is that the method should be responsible for one single thing, no matter how it is implemented. There can be myriad of things that a method needs to perform before doing the one single thing it responsible for.
The `build()` method is responsible for returning the build object. To do that it has to build the object and return it. This is true for the usual builder or perhaps for any builder pattern. The only difference is that the object returned by the `build()` method of this pattern is ready before the build process was finished. If you consider that it is even cleaner from your point of view than a normal builder. It does not alter in any way the built object. It does not mutate it. The `build()` method is not a mutator in that sense. It however cleans a reference to the built object so that it can not be given to anybody else but the real owner, the on, who first invoked `build()`.
On the other hand immutable objects get mutated during their build-up. Even Integers are somehow created and became immutable. And they actually do some caching for small integer numbers to gain some speed and on the other hand result a lot of possible surprises. I am not absolutely convinced that all the patterns followed by the design 20 years ago by Java language designers are still valid and the best solutions when the memory and CPU is more available and experience of good software design has developed a lot.
What you said doesn’t help with the fact that your build() method IS a mutator and accessor at the same time. Mutators mutate the current object’s state. It doesn’t have anything to do with the returned object.
Lastly, I’d like to point out another shortcoming of your builder. If the object has two fields in it that must be compared to each other to be certain that they meet the invariants, you’d be required to either take them both in at once and check them then, or you’d have to check in the build() method. Overall, you’re leaving the checking of invariants up to the builder, but I think that responsibilty should be solely up to the implementatipn.
The `build()` method is a mutator and an accessor. This is the only way you can implements some patterns. To name the simplest for example, the lazy singleton. Very true that singletons are questioned to be a good pattern, but for a totally different reason.
As for the “two fields”:
What you write is a special case when you build an object that has some constraints. In other words some parameters used in the build process just do not result a correct object. In that case some code has to check the consistency. Whether this code is inside the builder or in the built object is a different matter.
This is generally true exactly the same way for any builder pattern implementation. This is the own of the pattern itself and not the implementation. On the other hand the implementation of the verification can be in the builder as well as in the built object class. The location of the implementation of the verification is not restricted by this implementation in any other way.
When judging a pattern the main question is not whether the implementation or the pattern itself violates some generally agreed rules. If there is no reasoning and questioning about it, saying that a mutator accessor is bad is dogma. (Two legs versus four legs.) The main question I ask when I look at a pattern (in the order of importance, later is more important):
1. How much does it help to express the implementation of some problem?
2. How much can the consumer of the concrete implementation of the code implementing the pattern and thus providing the “API” use it in a wrong way?
3. How much can an implementer coding some implementation of the pattern can do it wrong misunderstanding the pattern?
Your comments are great help for me getting a better answer for some of these questions. Thank you.