32

I'm working on a problem where there are several implementations of Foo, accompanied by several FooBuilder's. While Foo's share several common variables that need to be set, they also have distinct variables that require their respective FooBuilder to implement some specific functionality. For succinctness, I'd like to have the FooBuilder's setters to use method chaining, like:

public abstract class FooBuilder {
  ...

  public FooBuilder setA(int A) {
    this.A = A;
    return this;
  }

  ...
}

and

public class FooImplBuilder extends FooBuilder{
  ...
  public FooImplBuilder setB(int B) {
    this.B = B;
    return this;
  }
  public FooImplBuilder setC(int C) {
    this.C = C;
    return this;
  }
  ...
}

And so on, with several different FooBuilder implementations. This technically does everything I want, however, this approach is sensitive to the order of methods calls when method chaining is performed. The following has method undefined compile errors:

someFoo.setA(a).setB(b)...

Requiring that the developer think about the order of method calls in the chain. To avoid this, I'd like to have the setters in FooBuilder somehow return the actual implementing subclass. However, I'm not sure how to do this. What is the best approach?

downer
  • 954
  • 2
  • 13
  • 24

3 Answers3

21

This is a good question and a real problem.

The easiest way to deal with it in Java likely involves the use of generics, as mentioned in Jochen's answer.

There's a good discussion of the issue and a reasonable solution in this blog entry on Using Inheritance with Fluent Interfaces, which combines generics with the definition of a getThis() method overriden in builder subclasses to solve the problem of always returning a builder of the correct class.

Don Roby
  • 40,677
  • 6
  • 91
  • 113
  • 1
    I like this solution. A lot more elaborate than what I proposed, but also way more flexible and ultimately elegant. – Jochen Jun 10 '12 at 14:19
  • Just to summarize the linked blog, and remove the separate builders: `public abstract class X>{public int a;public B setA(int foo){this.a=foo;return getThis();}public abstract B getThis();}public class Y extends X{public int b;public Y setB(int bar){this.b=bar;return getThis();}public Y getThis(){return this;}}` – Mark Jeronimus Oct 20 '14 at 17:49
16

Having found this excellent answer I am now sharing it around.

public class SuperClass<I extends SuperClass>
{
    @SuppressWarnings( "unchecked" ) // If you're annoyed by Lint.
    public I doStuff( Object withThings )
    {
        // Do stuff with things.
        return (I)this ; // Will always cast to the subclass. Causes the Lint warning.
    }
}

public class ImplementationOne
extends SuperClass<ImplementationOne>
{} // doStuff() will return an instance of ImplementationOne

public class ImplementationTwo
extends SuperClass<ImplementationTwo>
{} // doStuff() will return an instance of ImplementationTwo
Community
  • 1
  • 1
zerobandwidth
  • 1,213
  • 11
  • 18
5

Generics might be the way to go here.

If you declare setA() something like this (pseudo-code)

<T> T setA(int a)

the compiler should be able to figure out the real types, and if it doesn't you can give hints in the code like

obj.<RealFoo>setA(42)
Jochen
  • 2,277
  • 15
  • 22
  • 3
    +1: There's a good description of this tactic at http://egalluzzo.blogspot.com/2010/06/using-inheritance-with-fluent.html – Don Roby Jun 10 '12 at 12:46
  • 1
    The compiler is *not* able to figure out the type in chained method invocation, and repeating the type for each method invocation is hardly an option. – meriton Jun 10 '12 at 13:22
  • @DonRoby: Why don't you post that as an answer? It happens to be a better solution than Jochen's and would surely deserve an upvote ;-) – meriton Jun 10 '12 at 13:23