Saturday, May 19, 2012

Java: Builder Pattern in Inheritance

When to Use:

My use case is to build one or more immutable data models that inherit the same abstract class. The data model usually has too many properties to initialize them in a constructor so it's the excellent time to use a builder pattern.

How to Do It:

You may find a couple of examples to do a builder pattern with subclasses, but here I wanna have a simple and clean implementation that aims at data models.

Let's give it a try...

Parent Class without Builder: PurchaseItem

// Take three properties for example
public abstract class PurchaseItem implements Serializable {

    private final String itemNo;
    private final String itemName;
    private final Date itemCreateDate;

    protected <T extends PurchaseItem> PurchaseItem(Builder<T> builder) {
        this.itemNo = builder.itemNo();
        this.itemName = builder.itemName();
        this.itemCreateDate = builder.itemCreateDate();
    }

    public String getItemNo() {
        return itemNo;
    }

    public String getItemName() {
        return itemName;
    }

    public Date getItemCreateDate() {
        return (itemCreateDate != null) ? new Date(itemCreateDate.getTime()) : null;
    }
    
    // omit hashCode, equals, toString, serialVersionUID...
}

Child Class without Builder: GameSubscription

// An immutable class
public final class GameSubscription extends PurchaseItem {

    private final Long duration;
    private final DurationUnit durationUnit;
    
    public enum DurationUnit {
        MONTH, UNDEFINED
    }

    private GameSubscription(Builder builder) {
        super(builder);

        this.duration = builder.duration();
        this.durationUnit = builder.durationUnit();
    }

    public Long getDuration() {
        return duration;
    }

    public DurationUnit getDurationUnit() {
        return durationUnit;
    }
    
    // omit hashCode, equals, toString, serialVersionUID...
}

I think the code is pretty self-explained. The PurchaseItem class defines a bunch of common properties used by its subclasses. However, there is no setter provided so let's see how a builder involves in...

Parent Class with Builder: PurchaseItem


public abstract class PurchaseItem implements Serializable {
    
    // omit properties, getters
    
    public static class Builder<T extends PurchaseItem> {
        private final Class<T> itemClass;

        // Declare properties to avoid complaining private access in Java 7
        private String itemNo;
        private String itemName;
        private Date itemCreateDate;

        protected Builder(Class<T> itemClass) {
            this.itemClass = itemClass;
        }

        public Builder<T> itemNo(String itemNo) {
            this.itemNo = itemNo;
            return this;
        }

        public Builder<T> itemName(String itemName) {
            this.itemName = itemName;
            return this;
        }

        public Builder<T> itemCreateDate(Date itemCreateDate) {
            if (itemCreateDate != null) {
                this.itemCreateDate = new Date(itemCreateDate.getTime());
            }
            return this;
        }

        public T build() {
            try {
                Constructor<T> constructor = null;
                constructor = itemClass.getDeclaredConstructor(getClass());
                constructor.setAccessible(true);

                return constructor.newInstance(this);

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

The parent builder provides a constructor for a generic subclass so the parent builder can set the properties belong to it. Also, the parent builder provides a build method to get the subclass.

Child Class with Builder: GameSubscription


public final class GameSubscription extends PurchaseItem {

    // omit properties, getters
    
    public static final class Builder extends PurchaseItem.Builder<GameSubscription> {

        private Long duration;
        private DurationUnit durationUnit;

        public Builder() {
            super(GameSubscription.class);
        }

        public Builder duration(Long duration) {
            this.duration = duration;
            return this;
        }

        public Builder durationUnit(DurationUnit durationUnit) {
            this.durationUnit = durationUnit;
            return this;
        }

    }
}

The subclass builder can do set properties easily. It just needs to extend the parent builder and provide a subclass type. Then it's done!

How to Use It:

The example shows how to create an immutable object from a domain object.

class FooUtils {

    public static GameSubscription toGameSubscription(com.foo.domain.GameSubscription domainSub) {
        if (domainSub == null) {
            return null;
        }

        return toPurchaseItem(new GameSubscription.Builder()
                .duration(domainSub.getDuration())
                .durationUnit(toDurationUnit(domainSub.getDurationUnit())), domainSub)
                .build();
    }


    private static <T extends PurchaseItem> PurchaseItem.Builder<T> toPurchaseItem(
            PurchaseItem.Builder<T> builder, com.foo.domain.PurchaseItem domainItem) {
        return builder
                .itemNo(domainItem.getId())
                .itemName(domainItem.getItemName())
                .itemCreateDate(copyDate(domainItem.getItemCreateDate()));
    }
}

Here I made a toPurchaseItem method to make more reusable for different subclasses. The interesting part is that the visibility of a subclass builder is different from a parent builder. So the subclass builder has to be used first; otherwise, once the parent builder is returned, you will not be able to set subclass properties.

That's it. Hope it's simple enough... :D