I have a generic interface Handler
public interface Handler {
void handle(T obj);
}
I can have n implementations of this interface. Let's say I have following 2 implementations for now. One which handles String objects and another handles Date
public class StringHandler implements Handler {
@Override
public void handle(String str) {
System.out.println(str);
}
}
public class DateHandler implements Handler {
@Override
public void handle(Date date) {
System.out.println(date);
}
}
I want to write a factory which will return handler instances based on the class type. Something like this :
class HandlerFactory {
public Handler getHandler(Class clazz) {
if (clazz == String.class) return new StringHandler();
if (clazz == Date.class) return new DateHandler();
}
}
I get following error in this factory :
Type mismatch: cannot convert from StringHandler to Handler
How to fix this?
解决方案
SIMPLE SOLUTION
You could save your mappings Class -> Handler in a Map. Something like:
Map, Handler> registry = new HashMap<>();
public void registerHandler(Class dataType, Class extends Handler> handlerType) {
registry.put(dataType, handlerType);
}
public Handler getHandler(Class clazz) {
return registry.get(clazz).newInstance();
}
In some place, initialize handlers (could be in the factory itself):
factory.registerHandler(String.class, StringHandler.class);
factory.registerHandler(Date.class, DateHandler.class);
And in another place, you create and use them:
Handler stringhandler = factory.getHandler(String.class);
Handler dateHandler = factory.getHandler(Date.class);
MORE COMPLEX SOLUTION
You can "scan" classes using reflection and, instead of register manually the mappings Class -> Handler, do it using reflection.
for (Class extends Handler> handlerType : getHandlerClasses()) {
Type[] implementedInterfaces = handlerType.getGenericInterfaces();
ParameterizedType eventHandlerInterface = (ParameterizedType) implementedInterfaces[0];
Type[] types = eventHandlerInterface.getActualTypeArguments();
Class dataType = (Class) types[0]; //
factory.registerHandler(dataType, handlerType);
}
Then, you create and use them like above:
Handler stringhandler = factory.getHandler(String.class);
Handler dateHandler = factory.getHandler(Date.class);
To implement getHandlerClasses(), look at this to scan all classes in your jar. For each class, you have to check if it is a Handler:
if (Handler.class.isAssignableFrom(scanningClazz) //implements Handler
&& scanningClazz.getName() != Handler.class.getName()) //it is not Handler.class itself
{
//is a handler!
}
Hope it helps!