It’s been a while since my last post, so let’s take a look at how we can abuse the Builder pattern in Java and Android!

Builder Pattern?

If you’ve dabbled even just a bit with Android, you’ve probably seen the builder pattern in action. In short, the pattern consists of a Builder class which you use to construct an object of another class. For instance in Android the pattern is used when you create a dialog:

// Create the builder
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());

// Build the object
builder.setTitle("Warning!")
       .setMessage("You're about to destroy your phone. Proceed?")
       .setPositiveButton("Yeah", destroyClickListener)
       .setNegativeButton("Nah", null)
       .create() // <-- AlertDialog created!
       .show();

Seems rather simple! The best part is, your builder could provide default values for properties (e.g. default title text), and you can create multiple similar objects using the one and same builder. Neat! But wait, how does this all work under the hood?

Builders VS constructors

Let’s take a simple example: you want a nifty way to create game NPCs. The NPCs each have a distinct name. Our NPC class could look like this:

public class NPC {
    private String name;

    public NPC(String name) {
        this.name = name;
    }
}

So far so good. But wait, our NPCs each have a gender! Let’s add that:

public class NPC {
    private String name;
    private boolean male;

    public NPC(String name, boolean isMale) {
        this.name = name;
        this.male = isMale;
    }
}

Still manageable. But now we’d like to have height, color of eyes, color of hair, sexual preference and the favorite color for each NPC. Sigh…

public class NPC {
    private String name;
    private boolean male;
    private float height;
    private Color eyeColor;
    private Color hairColor;
    private String sexualPreference;
    private Color favoriteColor;

    public NPC(String name,
               boolean isMale,
               float height,
               Color eyeColor,
               Color hairColor,
               String sexualPreference,
               Color favoriteColor) {
        this.name = name;
        this.isMale = male;
        this.height = height;
        this.eyeColor = eyeColor;
        this.hairColor = hairColor;
        this.sexualPreference = sexualPreference;
        this.favoriteColor = favoriteColor;
    }
}

Ehh… Not that nice anymore. So, let’s take a builder to aid us! A basic builder would look like this:

// Awesome builder for our NPCs
public class Builder {

    public Builder() {

    }

    // Creates a new NPC
    public NPC build() {
        return new NPC();
    }
}

There’s nothing fancy here yet - just a barebones builder you can use like this:

Builder builder = new Builder();

NPC shopkeeper = builder.build();
NPC blacksmith = builder.build();

Nice! But all the NPCs are still the same. Let’s add a way of naming the NPCs:

public class Builder {

    private String name;

    public Builder() {

    }

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

    public NPC build() {
        return new NPC(this.name);
    }
}

Do note that the name() method returns the builder itself. This is useful for method chaining - let’s get back to that in a moment.

Now we can name the NPCs whatever we like:

Builder builder = new Builder();

NPC shopkeeper = builder.name("Greedy Sven").build();
NPC blacksmith = builder.name("Haegrid the Soot-faced").build();

See where we’re heading? We can now name each NPC how we like! Let’s just do a small change to our builder and NPC classes - let’s pass the builder as an argument to the NPC, and let’s also make the builder an inner static class of NPC:

public class NPC {
    private String name;

    // Note the private constructor!
    private NPC(NPC.Builder builder) {
        // Get the name from the builder
        this.name = builder.name;
    }

    public static class Builder {
        private String name;

        public Builder() {

        }

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

        public NPC build() {
            // Pass the builder to the NPC as a parameter
            return new NPC(this);
        }
    }
}

Now, if you try to construct an NPC without a builder, you… well, you can’t. We marked our NPC’s constructor as private, so it can only be called from the “inside”. Now, the usage changed only slightly:

// NPC.Builder instead of just Builder
NPC.Builder builder = new NPC.Builder();

NPC shopkeeper = builder.name("Greedy Sven").build();

To wrap it all up, let’s add all the original fields to our NPC and Builder classes AND let’s make some of the fields have a default value:

public class NPC {
    private String name;
    private boolean male;
    private float height;
    private Color eyeColor;
    private Color hairColor;
    private String sexualPreference;
    private Color favoriteColor;

    private NPC(Builder builder) {
        this.name = builder.name;
        this.male = builder.male;
        this.height = builder.height;
        this.eyeColor = builder.eyeColor;
        this.hairColor = builder.hairColor;
        this.sexualPreference = builder.sexualPreference;
        this.favoriteColor = builder.favoriteColor;
    }

    public static class Builder {
        private String name;
        private boolean male;
        private float height;
        private Color eyeColor = Color.GREEN;
        private Color hairColor = Color.POO;
        private String sexualPreference = "Carnivore";
        private Color favoriteColor = Color.OCTARINE;

        public Builder() {

        }

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

        public Builder male() {
            this.male = true;
            return this;
        }

        public Builder female() {
            this.male = false;
            return ths;
        }

        public Builder height(float height) {
            this.height = height;
            return this;
        }

        public Builder eyes(Color eyeColor) {
            this.eyeColor = eyeColor;
            return this;
        }

        public Builder hair(Color hairColor) {
            this.hairColor = hairColor;
            return this;
        }

        public Builder prefers(String preference) {
            this.sexualPreference = preference;
            return this;
        }

        public Builder favoriteColor(Color favColor) {
            this.favoriteColor = favColor;
            return this;
        }

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

Phew! A bit lengthy example, but it really pays off. Let’s have a look at how we’ll use this newly-introduced builder:

NPC.Builder builder = new NPC.Builder();

// A default NPC
NPC justSomeGal = builder.build();

// A black-haired man with some odd hobbies
NPC duckLover = builder.male().prefers("Poultry").hair(Color.BLACK).build();

// ... and his wife, who also has the same hobby and black hair
NPC duckLoversWife = builder.female().build();

It becomes really easy to adjust the parameters, to create similar objects, and the creation becomes more legible.

Conclusion

Builders are a neat way of constructing complex objects. They’re an awesome solution if you ever have a big list of properties you want to define for an object. For classes with just one or two constructor arguments, you’re better off without a builder - either create the objects directly or use a static factory method.