我有一个使用Generics的HTTP客户端类。我想创建一个带有(key,value) => (String type,HttpClient)的映射的工厂类。
HttpClient类有一个函数,它根据泛型类类型向服务器发送数据。本质上,我想要的是一个发送数据的泛型类,仅此而已。
问题是,我有多个类,我希望使用一个工厂类,以便:
HttpClient<Some Object>类的相同实例。请参阅下面的代码:
工厂
public class SystemPreferencesFactory {
private static SystemPreferencesFactory factory = null;
private Map<String, PreferencesHTTPClient<? extends ISystemPreferences>> preferencesMap;
private SystemPreferencesFactory(){
this.preferencesMap = Map.of
(PreferencesHTTPType.DUT_PREFERENCES.getName(), new PreferencesHTTPClient<DutPreferencesDTO>(PreferencesHTTPType.DUT_PREFERENCES.getUrl()),
PreferencesHTTPType.MACHINE_PROPERTIES.getName(), new PreferencesHTTPClient<MachineProperties>(PreferencesHTTPType.MACHINE_PROPERTIES.getUrl())
);
}
public static PreferencesHTTPClient<? extends ISystemPreferences> getPreferencesHTTPClient(String type) {
if (factory == null) {
factory = new SystemPreferencesFactory();
}
return factory.preferencesMap.get(type);
}
}HttpClient
public class PreferencesHTTPClient<T> extends HTTPClient {
private static final Logger logger = LoggerManager.getLogger();
private static String route = "";
public PreferencesHTTPClient(String route){
this.route = route;
}
public Future<HttpResponse> put(T dto) {
try {
System.err.println(dto.getClass());
HttpPut request = new HttpPut(URIAffix + route + "/" + SystemPreferences.systemPreferences().getSetupName());
request.addHeader("Authorization", authorizationPassword);
request.addHeader("Content-Type","application/json");
request.setEntity(new StringEntity(objectMapper.writeValueAsString(dto)));
return getClient().execute(request,
new FutureCallback<>() {
@Override
public void completed(final HttpResponse response) {
logger.info("update request succeeded");
}
@Override
public void failed(Exception ex) {
logger.error("update request failed: {}", ex.getMessage());
}
@Override
public void cancelled() {
logger.error("update request canceled");
}
});
} catch (JsonProcessingException | UnsupportedEncodingException e) {
logger.error("update request failed: {}", e.getMessage());
}
return CompletableFuture.completedFuture(null);
}
}当我尝试在main中调用它时,我会得到一个编译错误。
SystemPreferencesFactory.getPreferencesHTTPClient(PreferencesHTTPType.DUT_PREFERENCES.getName())
.put(converterUtil.DutFromEntityToDTO(dp));编译错误是:
Required type:
capture of ? extends ISystemPreferences
Provided:
DutPreferencesDTO我的DutPreferencesDTO类声明如下:
public class DutPreferencesDTO implements ISystemPreferences我的语法有什么问题?
发布于 2021-07-25 14:35:36
我们可以如下所示修改getPreferencesHTTPClient:
public class SystemPreferencesFactory {
...
// Change to generic method
public static <T extends ISystemPreferences> PreferencesHTTPClient<T> getPreferencesHTTPClient(String type) {
if (factory == null) {
factory = new SystemPreferencesFactory();
}
// cast result explicitly
return (PreferencesHTTPClient<T>) factory.preferencesMap.get(type);
}
public static void main(String[] args) {
SystemPreferencesFactory.getPreferencesHTTPClient(PreferencesHTTPType.DUT_PREFERENCES.name())
.put(new DutPreferencesDTO());
// Oops wrong dto still compiles
SystemPreferencesFactory.getPreferencesHTTPClient(PreferencesHTTPType.DUT_PREFERENCES.name())
.put(new MachineProperties());
// Assign to a local variable to infer
PreferencesHTTPClient<DutPreferencesDTO> preferencesHTTPClient = SystemPreferencesFactory.getPreferencesHTTPClient(PreferencesHTTPType.DUT_PREFERENCES.name());
preferencesHTTPClient.put(new DutPreferencesDTO());
// Compile error;
preferencesHTTPClient.put(new MachineProperties());
// Use type witness to guard
SystemPreferencesFactory
.<DutPreferencesDTO>getPreferencesHTTPClient(PreferencesHTTPType.DUT_PREFERENCES.name())
// Compile error;
.put(new MachineProperties());
}
}看上去还不错。但正如主要方法所示,有一个缺点。
我们需要在调用时显式地推断类型,以获得所需的类型检查。但是使用此方法的其他人可能容易忘记这样做,并且在调用put方法时可能会放置错误的DTO类型。
因此,为了避免这样的问题,我们使用DTO的类,而不是getPreferencesHTTPClient中的String,如下所示:
public class SystemPreferencesFactorySafe {
private static SystemPreferencesFactorySafe factory = null;
private Map<Class<?>, PreferencesHTTPClient<? extends ISystemPreferences>> preferencesMap;
private SystemPreferencesFactorySafe() {
this.preferencesMap = Map.of
(DutPreferencesDTO.class, new PreferencesHTTPClient<DutPreferencesDTO>(PreferencesHTTPType.DUT_PREFERENCES.getUrl()),
MachineProperties.class, new PreferencesHTTPClient<MachineProperties>(PreferencesHTTPType.MACHINE_PROPERTIES.getUrl())
);
}
// T is inferred by type this time
public static <T extends ISystemPreferences> PreferencesHTTPClient<T> getPreferencesHTTPClient(Class<T> type) {
if (factory == null) {
factory = new SystemPreferencesFactorySafe();
}
return (PreferencesHTTPClient<T>) factory.preferencesMap.get(type);
}
public static void main(String[] args) {
SystemPreferencesFactorySafe.getPreferencesHTTPClient(DutPreferencesDTO.class)
.put(new DutPreferencesDTO());
// Good we see compile error.
SystemPreferencesFactorySafe.getPreferencesHTTPClient(DutPreferencesDTO.class)
.put(new MachineProperties());
}
}由于该类型是使用该参数推断的,因此当某人放置错误的DTO类型时,我们不需要显式推断获得编译错误。
https://stackoverflow.com/questions/68517197
复制相似问题