我在使用特定用例的泛型实现工厂时遇到了麻烦
我有模型类:
class BaseModel { }
class ModelA extends BaseModel { }
class ModelB extends BaseModel { }
相应的服务:
class Service<T extends BaseModel> { }
class ServiceA extends Service<ModelA> {}
class ServiceB extends Service<ModelB> {}
我的工厂类,根据它所服务的模型创建服务:
class Factory {
private Map<Class<? extends BaseModel>, Class<? extends Service>> registry;
Factory(){
registry = new HashMap<>();
registry.put(ModelA.class, ServiceA.class);
registry.put(ModelB.class, ServiceB.class);
}
Service getService(Class<? extends BaseModel> clazz) throws IllegalAccessException, InstantiationException {
return registry.get(clazz).newInstance();
}
}
使用工厂的课程
class Handler<T extends BaseModel>{
private Service<T> myService;
Handler(Class<T> modelClass) {
Factory fact = new Factory();
try {
myService = fact.getService(modelClass);
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
我收到使用工厂获取服务的行的警告:
"Unchecked assignment 'Service' to 'Service<T>'"
我理解为什么会收到消息,因为getService
方法返回Service
,但我需要Service<T>
并且对如何更改代码以获取Service<T>
感到困惑
有什么建议吗?
谢谢!
答案 0 :(得分:1)
在这里,您可以将类捕获为T并返回它的实例(使用强制转换):
<T extends BaseModel> Service<T> getService(Class<T> clazz) throws IllegalAccessException, InstantiationException {
return (Service<T>) registry.get(clazz).newInstance();
}
答案 1 :(得分:0)
Java泛型和继承有时会反直觉地交互,即Service<ModelA>
与Service<BaseModel>
无关(就继承而言)。但是,您可以编写getService()
的两个实现并显式调用服务构造函数(而不是通过反射)。您的处理程序将需要您的模型的实例,以便Java重写将为您选择正确的服务构造函数。
我在原始答案中没有想到的是:您需要捕获工厂中的所有BaseModel实现(覆盖将选择最具体的方法),并且还必须针对接口实现您的服务以拉动字符串在一起。
class BaseModel { }
class ModelA extends BaseModel { }
class ModelB extends BaseModel { }
interface Service { }
class ServiceImplementation<T extends BaseModel> implements Service { }
class ServiceFactory {
public static Service getService(ModelA model) { return new ServiceImplementation<ModelA>(); }
public static Service getService(ModelB model) { return new ServiceImplementation<ModelB>(); }
public static Service getService(BaseModel model) {
throw new UnsupportedOperationException("Unknown Service Model");
}
}
class Handler<T extends BaseModel> {
private Service service;
Handler(T model) {
service = ServiceFactory.getService(model);
}
}