我有一个通用界面处理程序
public interface Handler<T> {
void handle(T obj);
}
我可以有这个界面的n个实现。让我们说我现在有以下2个实现。一个处理String对象,另一个处理Date
public class StringHandler implements Handler<String> {
@Override
public void handle(String str) {
System.out.println(str);
}
}
public class DateHandler implements Handler<Date> {
@Override
public void handle(Date date) {
System.out.println(date);
}
}
我想编写一个工厂,它将根据类类型返回处理程序实例。像这样:
class HandlerFactory {
public <T> Handler<T> getHandler(Class<T> clazz) {
if (clazz == String.class) return new StringHandler();
if (clazz == Date.class) return new DateHandler();
}
}
我在这家工厂遇到以下错误:
类型不匹配:无法从
StringHandler
转换为Handler<T>
如何解决这个问题?
答案 0 :(得分:7)
简单解决方案
您可以在Class<T> -> Handler<T>
中保存映射Map
。类似的东西:
Map<Class<T>, Handler<T>> registry = new HashMap<>();
public void registerHandler(Class<T> dataType, Class<? extends Handler> handlerType) {
registry.put(dataType, handlerType);
}
public <T> Handler<T> getHandler(Class<T> clazz) {
return registry.get(clazz).newInstance();
}
在某些地方,初始化处理程序(可能在工厂本身):
factory.registerHandler(String.class, StringHandler.class);
factory.registerHandler(Date.class, DateHandler.class);
在另一个地方,你创建并使用它们:
Handler<String> stringhandler = factory.getHandler(String.class);
Handler<Date> dateHandler = factory.getHandler(Date.class);
更复杂的解决方案
你可以扫描&#34;使用反射的类,而不是手动注册映射Class<T> -> Handler<T>
,使用反射来完成。
for (Class<? extends Handler> handlerType : getHandlerClasses()) {
Type[] implementedInterfaces = handlerType.getGenericInterfaces();
ParameterizedType eventHandlerInterface = (ParameterizedType) implementedInterfaces[0];
Type[] types = eventHandlerInterface.getActualTypeArguments();
Class dataType = (Class) types[0]; // <--String or Date, in your case
factory.registerHandler(dataType, handlerType);
}
然后,您可以像上面一样创建和使用它们:
Handler<String> stringhandler = factory.getHandler(String.class);
Handler<Date> dateHandler = factory.getHandler(Date.class);
要实施getHandlerClasses()
,请查看this以扫描jar
中的所有课程。对于每个班级,您必须检查它是否为Handler
:
if (Handler.class.isAssignableFrom(scanningClazz) //implements Handler
&& scanningClazz.getName() != Handler.class.getName()) //it is not Handler.class itself
{
//is a handler!
}
希望它有所帮助!
答案 1 :(得分:2)
你的问题是编译器无法实现结果类型 正确的事实。
为了帮助编译器,您可以让工厂委托构造。虽然这看起来很奇怪而且笨拙,但它确实能够在不牺牲诸如投射或使用?
或原始类型的情况下正确维护类型安全。
public interface Handler<T> {
void handle(T obj);
}
public static class StringHandler implements Handler<String> {
@Override
public void handle(String str) {
System.out.println(str);
}
}
public static class DateHandler implements Handler<Date> {
@Override
public void handle(Date date) {
System.out.println(date);
}
}
static class HandlerFactory {
enum ValidHandler {
String {
@Override
Handler<String> make() {
return new StringHandler();
}
},
Date {
@Override
Handler<Date> make() {
return new DateHandler();
}
};
abstract <T> Handler<T> make();
}
public <T> Handler<T> getHandler(Class<T> clazz) {
if (clazz == String.class) {
return ValidHandler.String.make();
}
if (clazz == Date.class) {
return ValidHandler.Date.make();
}
return null;
}
}
public void test() {
HandlerFactory factory = new HandlerFactory();
Handler<String> stringHandler = factory.getHandler(String.class);
Handler<Date> dateHandler = factory.getHandler(Date.class);
}
答案 2 :(得分:0)
您可以使用以下内容:
class HandlerFactory {
public <T> Handler<T> getHandler(Class<T> clazz) {
if (clazz.equals(String.class)) return (Handler<T>) new StringHandler();
if (clazz.equals(Date.class)) return (Handler<T>) new DateHandler();
return null;
}
}
T
是通用的,编译器无法在编译时映射它。使用.equals
代替==
也更安全。
答案 3 :(得分:0)
使用泛型类型的重点是共享实现。如果您的Handler界面的n实现是如此不同以至于无法共享,那么我认为没有任何理由首先使用定义通用接口。您只需要将StringHandler和DateHandler作为顶级类。
另一方面,如果可以共享实现,就像您的示例一样,那么工厂自然会工作:
public class Main {
static public interface Handler<T> {
void handle(T obj);
}
static public class PrintHandler<T> implements Handler<T> {
@Override
public void handle(T obj) {
System.out.println(obj);
}
}
static class HandlerFactory {
public static <T> Handler<T> getHandler() {
return new PrintHandler<T>();
}
}
public static void main(String[] args) {
Handler<String> stringHandler = HandlerFactory.getHandler();
Handler<Date> dateHandler = HandlerFactory.getHandler();
stringHandler.handle("TEST");
dateHandler.handle(new Date());
}
}
答案 4 :(得分:-1)
基本上你可以这样做:
public Handler getHandler( Class clazz ){
if( clazz == String.class ) return new StringHandler();
if( clazz == Date.class ) return new DateHandler();
return null;
}
public static void main( String[] args ){
HandlerFactory handlerFactory = new HandlerFactory();
StringHandler handler = ( StringHandler )handlerFactory.getHandler( String.class );
handler.handle( "TEST" );
DateHandler handler2 = ( DateHandler )handlerFactory.getHandler( Date.class );
handler2.handle( new Date() );
}
输出:
TEST
Tue Dec 15 15:31:00 CET 2015
但是,编写两种不同的方法来分别获取处理程序总是一种更好的方法。
答案 5 :(得分:-1)
我编辑了你的代码并允许Eclipse去修复&#34;错误,它提出了这个。
scala> val filePath = getClass.getResource("myImage.png")
filePath: java.net.URI = file:/home/robert/myImage.png
答案 6 :(得分:-1)
Yout HandlerFactory不了解T.使用您的工厂如下 -
public class HandlerFactory {
public Handler<?> getHandler(Class<?> clazz) {
if (clazz == String.class) {
return new StringHandler();
}
if (clazz == Date.class) {
return new DateHandler();
}
return null;
}
}