One of my more interesting tasks of the past few weeks was to refactor an existing method to use Generics in a method's return type and simplify the readability of code that calls the method.
The starting point was this method:
public static Object getHandler(Class<?> aClass) throws HandlerException {
if (handlerFactory == null)
handlerFactory = new HandlerFactory();
return handlerFactory.getHandler(aClass);
}
Obviously, this code is headed in a positive direction. Creation of a specific instance of a Handler is delegated to a class in a Factory design pattern. It also has been built with a hint of Generics, with the "Class<?>" as the type of the parameter.
The problems we had with clients who called this method was that they:
(1) needed to cast to the Class being passed in; and
(2) needed to wrap the call in a try/catch block, even though the catch actions were always identical.
Calls to this method wound up looking like this, a chunk of code that we set out to simplify:
try {
handler = (SomeHandler) RunContext.getHandler(SomeHandler.class);
} catch (HandlerException e) {
// raise an alert or something, always the same thing
}
Our goal was to simplify the calling code to a single, reasonably clear line. We made that possible by improving the use of Java Generics in the method, returning a Generics-based return type rather than Object, and by moving the try/catch block with identical catches into the method itself. Something like:
SomeHandler handler = RunContext.getHandler(SomeHandler.class);
We replaced the Object return type with T, and defined it to be the same type identified by the input parameter. And we used the cast() method to convert the Factory's returned object to our T. The final result:
public static <T> T getHandler(Class<T> type) {
if (handlerFactory == null)
handlerFactory = new HandlerFactory();
T handler = null;
try {
handler = type.cast( handlerFactory.getHandler(type) );
} catch (HandlerException e) {
// Do the always-the-same Exception thing here
}
return handler;
}
The starting point was this method:
public static Object getHandler(Class<?> aClass) throws HandlerException {
if (handlerFactory == null)
handlerFactory = new HandlerFactory();
return handlerFactory.getHandler(aClass);
}
Obviously, this code is headed in a positive direction. Creation of a specific instance of a Handler is delegated to a class in a Factory design pattern. It also has been built with a hint of Generics, with the "Class<?>" as the type of the parameter.
The problems we had with clients who called this method was that they:
(1) needed to cast to the Class being passed in; and
(2) needed to wrap the call in a try/catch block, even though the catch actions were always identical.
Calls to this method wound up looking like this, a chunk of code that we set out to simplify:
try {
handler = (SomeHandler) RunContext.getHandler(SomeHandler.class);
} catch (HandlerException e) {
// raise an alert or something, always the same thing
}
Our goal was to simplify the calling code to a single, reasonably clear line. We made that possible by improving the use of Java Generics in the method, returning a Generics-based return type rather than Object, and by moving the try/catch block with identical catches into the method itself. Something like:
SomeHandler handler = RunContext.getHandler(SomeHandler.class);
We replaced the Object return type with T, and defined it to be the same type identified by the input parameter. And we used the cast() method to convert the Factory's returned object to our T. The final result:
public static <T> T getHandler(Class<T> type) {
if (handlerFactory == null)
handlerFactory = new HandlerFactory();
T handler = null;
try {
handler = type.cast( handlerFactory.getHandler(type) );
} catch (HandlerException e) {
// Do the always-the-same Exception thing here
}
return handler;
}