首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java -泛型工厂类

Java -泛型工厂类
EN

Stack Overflow用户
提问于 2021-07-25 09:18:35
回答 1查看 118关注 0票数 1

我有一个使用Generics的HTTP客户端类。我想创建一个带有(key,value) => (String type,HttpClient)的映射的工厂类。

HttpClient类有一个函数,它根据泛型类类型向服务器发送数据。本质上,我想要的是一个发送数据的泛型类,仅此而已。

问题是,我有多个类,我希望使用一个工厂类,以便:

  1. 简化了HttpClient对象的创建。
  2. 一直避免使用"new“关键字,因为我可以在整个应用程序中使用HttpClient<Some Object>类的相同实例。

请参阅下面的代码:

工厂

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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中调用它时,我会得到一个编译错误。

代码语言:javascript
运行
复制
SystemPreferencesFactory.getPreferencesHTTPClient(PreferencesHTTPType.DUT_PREFERENCES.getName())
                 .put(converterUtil.DutFromEntityToDTO(dp));

编译错误是:

代码语言:javascript
运行
复制
Required type:
capture of ? extends ISystemPreferences
Provided:
DutPreferencesDTO

我的DutPreferencesDTO类声明如下:

代码语言:javascript
运行
复制
public class DutPreferencesDTO implements ISystemPreferences

我的语法有什么问题?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-25 14:35:36

我们可以如下所示修改getPreferencesHTTPClient

代码语言:javascript
运行
复制
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,如下所示:

代码语言:javascript
运行
复制
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类型时,我们不需要显式推断获得编译错误。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68517197

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档