Mar 022012
 

The builder pattern is great, isn’t it? It lets you create nice immutable classes without the need for multiple constructors and it gives the API users freedom in choosing which arguments they want to use when creating the instance. But what happens when you want to tell the user that she must call one builder method or the other, since it is crucial for the class you’re trying to build? The builder pattern simply doesn’t have such a feature. This post will try to give an alternative solution to this problem.

But lets take it from the beginning.

Part 1: Why builder pattern?

Suppose you want to create a class name Address. And suppose you want it to have fields like protocol, url, port, path and description. Now, you want to give your users the freedom to choose which arguments to pass when creating an instance of the class. Also, you want to make your class immutable, so set methods are out of the question. You might start up with something like:

public class Address {
    private String protocol;
    private String url;
    private int port;
    private String path;
    private String description;

    public Address(String url, int port) {}
    public Address(String protocol, String url, int port) {}
    public Address(String protocol, String url, int port, String path) {}
    public Address(String protocol, String url, int port, String path, String description) {}
}

…but you start realizing there is a problem here. First, maybe you need more combinations, like creating an instance given an url, a port and a path, but – both url and path are Strings, and you already have a constructor which takes two String and an int, and, hey, you know you can’t have two constructors with the same signature! Secondly, you realize there’s simply too many constructors here, and it reminds you of something you read once in a book about code smells. The book suggests solving this by replacing constructors with creation methods. Using this tip, your class might look like this:

public class Address {
    private String protocol;
    private String url;
    private int port;
    private String path;
    private String description;

    // no one should use this outside your class
    private Address() {}

    public Address createAddressWithProtocolUrlAndPort(String protocol, String url, int port) {}
    public Address createAddressWithProtocolUrlPortAndPath(String protocol, String url, int port, String path) {}
    public Address createAddressWithUrlPortAndPath(String url, String path) {}
}

…but this is also tedious. There’s simply too many combinations. And you need to create an endlessly amount of factory methods to allow all of them. It is then that it strikes you! Why didn’t you consider using the builder pattern! This way, you don’t have to create loads of constructors or creation methods, and still allow the user to create an immutable instance of your class while freely choosing which arguments to use. Your beautiful new class now looks like that:

public class Address {
    private String protocol;
    private String url;
    private int port;
    private String path;
    private String description;

    // only builder should be able to create an instance
    private Address(Builder builder) {
        this.protocol = builder.protocol;
        this.url = builder.url;
        this.port = builder.port;
        this.path = builder.path;
        this.description = builder.description;
    }

    public static class Builder {
        private String protocol;
        private String url;
        private int port;
        private String path;
        private String description;

        public Builder protocol(String protocol) {
            this.protocol = protocol;
            return this;
        }

        public Builder url(String url) {
            this.url = url;
            return this;
        }

        public Builder port(int port) {
            this.port = port;
            return this;
        }

        public Builder path(String path) {
            this.path = path;
            return this;
        }

        public Builder description(String description) {
            this.description = description;
            return this;
        }

        public Address build() {
            return new Address(this);
        }
    }
    // TODO: add some get methods here...
}

…and you can create a new instance of Address by calling:

Address address = new Builder().url("www.google.com").port(80).build();

Happy? Very. But there’s just one tiny problem. What happens if the user of this class tries to create an Address without an url or a port? You simply cant allow that now, can you? So you start thinking. And you realize you simply cannot find a good solution. So you ask a question in Stackoverflow and hope someone would give you a good solution. Most of the answers you get there don’t help at all, but after a while, someone called pgras gives you this fantastic solution, and, well, you like it so much you decide to write a blog post about it :)

Part 2: Mandatory methods in builder pattern

The solution is to change you builder into a state machine. Each mandatory method in it leads you to the next step, until you get to the last step which includes both non-mandatory methods and the build method itself. It uses interfaces to define the different steps, and, well, it look like that:

public class Address {
    private String protocol;
    private String url;
    private int port;
    private String path;
    private String description;

    // only builder should be able to create an instance
    private Address(Builder builder) {
        this.protocol = builder.protocol;
        this.url = builder.url;
        this.port = builder.port;
        this.path = builder.path;
        this.description = builder.description;
    }

    public static Url builder() {
        return new Builder();
    }

    private static class Builder implements Url, Port, Build{
        private String protocol;
        private String url;
        private int port;
        private String path;
        private String description;

        /** Mandatory, must be followed by {@link Port#port(int)}  */
        public Port url(String url) {
            this.url = url;
            return this;
        }

        /** Mandatory, must be followed by methods in {@link Build}  */
        public Build port(int port) {
            this.port = port;
            return this;
        }

        /** Non-mandatory, must be followed by methods in {@link Build}  */
        public Build protocol(String protocol) {
            this.protocol = protocol;
            return this;
        }

        /** Non-mandatory, must be followed by methods in {@link Build}  */
        public Build path(String path) {
            this.path = path;
            return this;
        }

        /** Non-mandatory, must be followed by methods in {@link Build}  */
        public Build description(String description) {
            this.description = description;
            return this;
        }

        /** Creates an instance of {@link Address} */
        public Address build() {
            return new Address(this);
        }
    }

    interface Url {
        public Port url(String url);
    }

    interface Port {
        public Build port(int port);
    }

    interface Build {
        public Build protocol(String protocol);
        public Build path(String path);
        public Build description(String description);
        public Address build();
    }

    // TODO: add some get methods here...
}

Using it is simple:

Address address = Address.builder().url("www.google.com").port(80).build();

Try using it without the mandatory methods, and you get a compilation error:

Autocomplete is also helpful here, and will only give you the correct options:

So there you have it. The API user can now use your friendly API to create a robust and immutable class knowing that she’ll get all the help needed along the way, using autocomplete and compilation errors if she did something she wasn’t suppose to do. Nothing here can go wrong!

Thanks again, Stackoverflow and  pgras for this nice solution.

  2 Responses to “Builder pattern with a twist”

  1. Nice.
    A lot of boilerplate though.
    Also, I get compiler warnings for synthetic-access and hiding.

  2. Beautiful! Especially from the clients point of view. I can’t wait until I run into a design problem where I can use this version of the builder pattern :)

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>