Tuesday 2 August 2011

Using generics with a fluent API

I've recently worked on an integration project requiring a message API.  It was to be responsible for building messages of various types to be sent on a variety of transports. Each message had numerous parameters but some were only used in particular contexts. This meant that frequently you'd get constructors where some of those parameters had to be set to null to indicate they were not to be used. This is a code smell. One solution would be to use the refactoring 'Introduce parameter object'. This refactoring is used to group parameters together into immutable classes so those parameters have a common context.  This may alleviate the problem somewhat but in practice I found this resulted in several overloaded constructors each with different combinations of parameter objects. I needed another solution.

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

No comments:

Post a Comment