I've had some success in the past using fluent API with builders. A fluent interface is implemented by using method chaining to relay the instruction context of a subsequent call. My expectation was to create something like:
Some parameters were common to all message types so it made sense to have these in a base class.
The message base class:
and it's associated builder:
I then subclassed the builder class to create the specialized message types. For brevity most parameters have been omitted.
An example of a specialized message class with inherits all the properties of the base class along with its own parameters.
The builder for this class:
However to get the expected usage of:
I've had to subclass all withXXX methods from the Message base class. In this example, it's not too painful as there's only a couple of common parameters but more realistically I could have numerous parameters which means for each specialized subclass I need to override those methods. This approach quickly becomes unwieldy and a maintenance headache. To make sure that method chain returns the correct type I've had to resort to calling the super method and then return the correct type i.e this. Not very good.What I needed was for each subclass to inherit the super class methods implicitly but with the proviso that they return the actual type not the super type.
A solution is to use Self Bound GenericTypes. Angelika Langer gives a good explanation which she calls the getThis() trick.
The base MessageBuilder class has been changed to use self bound generic types. So for example, instead of hardwiring
withId()
to return the type of the builder that defines it, a type parameter B
is introduced and withId() returns B
via the abstract self() method. This self method implemented in the subclass to return the concrete type rather than the base type of the builder. The self-referential definition MessageBuilder<B extends MessageBuilder<B>>
allows the return type of the inherited withId()
in RequestBuilder
to be RequestBuilder
rather than MessageBuilder
.Now all the subclass has to do, in addition to its own fluent methods, is to provide an implementation of the self() method. Job done.
In this way, subclasses for builders only need be concerned with providing fluent methods for the parameters pertinent to that class. They will automatically inherit fluent methods from the super class so no overriding is required and the intent of the class is clearer. I can build up that message's fluent methods to set the parameters I actually need for that particular context without resorting to long unwieldy parameter lists. Again the intent is clearer. Result !
Thanks to a bit of tinkering, this solution seems elegant and understandable now but as usual with generics it'll be mostly incomprehensible tomorrow :).
Links