Practical Functional Java

Coda: Immutability Redux

Jeff Butler

github.com/jeffgbutler/practical-functional-java

Immutability Redux

How Inheritance Ruins Everything

All code examples in package examples.basics.lambdas.immutable.redux

Builders with Inheritance

  • When creating a hierarchy of immutable objects, you might also need a hierarchy of builders
  • That's when things get tricky
  • Suppose you have a typical hierarchy of Cat and Dog objects, both inheriting from AbstractAnimal...

We start out coding AbstractAnimal similarly to our previous examples...

          
public abstract class AbstractAnimal {

    private String name;
    private int age;
    
    protected AbstractAnimal(AbstractBuilder builder) {
        name = Objects.requireNonNull(builder.name);
        age = builder.age;
    }

    public abstract String sayHello();
    
    public static abstract class AbstractBuilder {
        private String name;
        private int age;

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

        public AbstractBuilder withAge(int age) {
            this.age = age;
            return this;
        }
        
// won't compile!
//        public AbstractAnimal build() {
//            return new AbstractAnimal(this);
//        }
    }
}
          
        

Problems

  • Won't compile with our normal build method
  • A more subtle problem - the with* builder methods lose the concrete class name
  • The solution is two fold:
    • The Curiously Recurring Template Pattern
    • The "getThis()" trick

AbstractAnimal coded with the curiously recurring template pattern and "getThis()"...

          
public abstract class BetterAbstractAnimal {

    private String name;
    private int age;
    
    protected BetterAbstractAnimal(AbstractBuilder<?> builder) {
        name = Objects.requireNonNull(builder.name);
        age = builder.age;
    }

    public abstract String sayHello();
    
    public static abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
        private String name;
        private int age;

        public T withName(String name) {
            this.name = name;
            return getThis();
        }

        public T withAge(int age) {
            this.age = age;
            return getThis();
        }
        
        protected abstract T getThis();
    }
}
          
        

Now we can code our Dog...

          
public class Dog extends BetterAbstractAnimal {
    
    private String akcRegistrationNumber;
    
    private Dog(Builder builder) {
        super(builder);
        akcRegistrationNumber = Objects.requireNonNull(builder.akcRegistrationNumber);
    }
    
    public String getAkcRegistrationNumber() {
        return akcRegistrationNumber;
    }

    @Override
    public String sayHello() {
        return "woof";
    }

    public static class Builder extends AbstractBuilder<Builder> {
        private String akcRegistrationNumber;
        
        public Builder withAkcRegistrationNumber(String akcRegistrationNumber) {
            this.akcRegistrationNumber = akcRegistrationNumber;
            return this;
        }
        
        @Override
        public Builder getThis() {
            return this;
        }
        
        public Dog build() {
            return new Dog(this);
        }
    }
}
          
        

Good References

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206

Thank You!

Please rate the session. Suggestions for improvements are very welcome.

jeffgbutler@gmail.com

github.com/jeffgbutler