GitHub   @OpenKivaKit Twitter Zulip Chat RSS Feed Java Code Geeks Mailing List

State(Art)

Jonathan's thoughts on the state of the art in software design.

2021.07.04

A (very) slightly simpler builder pattern  

Frank Kiwy recently published, in Java Magazine, the article Exploring Joshua Bloch’s Builder design pattern in Java: Bloch’s Builder pattern can be thought of as a workaround for a missing language feature. I have a fine point to make about the code example in this article. There is a way to eliminate a bit of repetition (mentioned in the article as a point of criticism of the pattern), making the code just a little easier to read and more succinct. The example in Frank’s article looks something like this (I’ve reduced the number of fields and changed the formatting, because I’m just like that):

public class Book 
{
    private final String isbn;
    private final String title;
    private final String author;
    
    private Book(Builder builder) 
    {
        this.isbn = builder.isbn;
        this.title = builder.title;
        this.author = builder.author;
    }

    public String getIsbn() 
    {
        return isbn;
    }

    public String getTitle() 
    {
        return title;
    }

    public String getAuthor() 
    {
        return author;
    }
    
    public static class Builder 
    {
        private final String isbn;
        private final String title;
        private String author;

        public Builder(String isbn, String title) 
        {
            this.isbn = isbn;
            this.title = title;
        }

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

        public Book build() 
        {
            return new Book(this);
        }
    }
}

My quibble is just that we can get rid of the duplicate fields in the Builder class in the code above by instead using an instance of Book. My version is a little bit simpler and clearer, doesn’t repeat assignments, and the line count drops from 52 lines in “Josh’s builder pattern” to 49 in mine (and with more fields there will be more difference). It is true that in my version, the fields in Book are no longer explicitly declared as final. However, this makes no practical difference because the fields can’t be mutated except by Builder. It is also true that it’s not possible to build multiple objects from the same builder by inheriting previous builder state, but that is “a feature, not a bug.” To build multiple related objects, consider instead The functional properties pattern.

public class Book 
{
    private String isbn;
    private String title;
    private String author;
    
    private Book() 
    {
    }

    public String getIsbn() 
    {
        return isbn;
    }

    public String getTitle() 
    {
        return title;
    }

    public String getAuthor() 
    {
        return author;
    }
    
    public static class Builder 
    {
        private Book book = new Book();

        public Builder(String isbn, String title) 
        {
            book.isbn = isbn;
            book.title = title;
        }

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

        public Book build() 
        {
            var built = book;
            book = new Book();
            return built;
        }
    }
}

Finally, yes, Frank is right that the builder pattern is a workaround for a missing language feature, and named parameters would be probably be welcomed. However it might be worth thinking about other approaches to this issue, such as my starting point for abolishing constructors or creating a language syntax for functional field updating similar to The functional properties pattern:

var spaceAliens = new Book() 
    with isbn = "81729387" 
    with title = "Space Aliens"
    with author = "Calvin and Hobbes";

This pattern would allow Book to be initialized clearly as with named parameters to a constructor but it would also permit new books to be functionally derived, as in:

var martians = spaceAliens with title = "Martians";


Questions? Comments? Tweet yours to @OpenKivaKit or post here:


Copyright © 2021 Jonathan Locke