Java – Generic factories

An example of using generics to tie together the return type of a Java factory method with its parameters.

Generics start for most Java developers as a means of providing type safety and eliminating casting when using collections, turning code like this:-

Into code like this:-

Unfortunately, for many Java developers, that’s also where generics finish, probably through a combination of the reduced profit from their other applications and the slightly Byzantine syntax you need to master to get it.

Object factories

Programming to an interface rather than an implementation and the use of factory methods to centralise the creation of implementations are basic good practice to be seen throughout many a code base. So, quite often, are rather brittle and verbose factory implementations which can be quickly improved using generics.

Here’s a typical example where we have a set of interfaces for value objects inheriting a common base, and an implementation for each served up via a factory method.

 

Sample Java factoried pbject hierarchy

 

One simple factory approach is to have a method (or even a class and method pair) per interface:-

This offers type-safety and no need to cast the results, but it generates factory bloat and additional code to maintain, since new factory methods have to be added when new types are introduced.

Another approach is to use a generic factory method returning the base interface type and creating the object based on a parameter:-

This keeps the factory bloat down but requires casting whenever the factory method is called:-

Adding generics

If you’ve seen this sort of code before you’ve probably also seen your code editor warning about Class being a raw-type. We can clean this up a little and make it more type-safe by parameterising our references to Class.

By specifying what our classes extend using wildcards we’ve introduced some type-safety and also removed the need to cast the object returned by the make() method, though since we’re still returning the base type we still need to cast the manufactured object in order to use it.

To alleviate this, instead of using wildcards we can use type parameters which name a parameterised raw type so it can be referenced multiple times in the signature, in this case for both the parameter and the return type:-

Here we’re defining a type T which extends Communication, specifying that our make() method returns an instance of that type and has a parameter which is a Class extending that type.

Which means that, since invocations of make() must now return an implementation of the supplied interface, we no longer need to cast our calls to it:-

 

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">