Core Java

Design Pattern: Immutable Embedded Builder

Last week I wrote about what makes a pattern anti-pattern. This week I present a design pattern… or wait… perhaps this is an anti-pattern. Or is it? Let’ see!

The builder pattern is a programming style when there is a class that build an instance of another. The original aim of the builder pattern is to separate the building process 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?

Reference: Design Pattern: Immutable Embedded Builder from our JCG partner Peter Verhas at the Java Deep blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

6 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Jake Zim
Jake Zim
10 years ago

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… Read more »

Peter Verhas
Peter Verhas
10 years ago

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… Read more »

Jake Zim
Jake Zim
10 years ago

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.

Peter Verhas
Peter Verhas
10 years ago

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… Read more »

Jake Zim
Jake Zim
10 years ago

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… Read more »

Peter Verhas
Peter Verhas
10 years ago

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… Read more »

Back to top button