【问题标题】:Problems with generics / system architecture using generics使用泛型的泛型/系统架构问题
【发布时间】:2011-06-04 16:47:55
【问题描述】:

也许我在理解泛型时遇到了一些问题,但我无法做一些对我来说看起来合乎逻辑的事情。也许你可以帮我澄清一下。

我正在开发一个 Java 库,并且有一个函数将调用一个平台,该平台将以 JSON 格式返回信息。我想创建一个名称空间,负责检索 JSON 信息并将其解析为业务对象。为此,我创建了这个:

JSON 类 - 有 2 个方法:

protected JSONObject readJsonFromUrl(String url)

打开流并下载 JSON 文件

public <T, U extends Parser> T readObjectFromUrl(String url, U parser) 

是“入口点”。会调用readJsonFromUrl,并将返回值调用给解析器。

Parser类是一个抽象类,有这个接口

public abstract class Parser {

public abstract <T> T parse(JSONObject jsonObject);
}

我想做的是创建一个覆盖 parse 方法的子类,每个子类将返回不同的类型。 例如,联系人列表解析器如下所示:

public <T> T parse(JSONObject jsonObject) {
ContactList contactList = new ContactList();

    //Simplified for clearness
    contactList = parse(jsonObject);

return contactList;
}

问题是:我得到一个编译器错误,因为它需要一个 T,而不是一个联系人列表。 如果我更改为 ,则新方法的签名与父类的签名不匹配。 如果我将contactList 的声明更改为T contactList;,我将无法调用一些我需要的方法(例如addContact)。

我是不是弄错了泛型?在这种情况下,它们适合我想要的吗? 如果不是,您将如何实现类似的功能?

谢谢, 奥斯卡

编辑:使用 Object 而不是泛型的最佳解决方案是什么?好像不太好看:(

【问题讨论】:

    标签: java generics architecture


    【解决方案1】:

    您在一个总是返回相同类型对象的方法上使用泛型,并且该类型可能会因方法的实现而异。

    那么我猜你应该把你的泛型声明移到类中。

    public abstract class Parser<T> {
        public abstract T parse(JSONObject jsonObject);
    }
    

    您的实现将如下所示:

    public class Impl extends Parser<ContactList>{
        public abstract ContactList parse(JSONObject jsonObject){
            ContactList contactList = new ContactList();
            //Simplified for clearness
            contactList = parse(jsonObject);
            return contactList;
        }
    }
    

    【讨论】:

      【解决方案2】:

      您可能想看看 Google Guice 如何实现 Injector.getInstance 方法:

      <T> T getInstance(Class<T> type);
      

      这允许用户写:

      ContactList contactList = injector.getInstance(ContactList.class);
      

      将此模式应用于您的解析器,我认为您可以避免为您要解析的每种类型创建不同的解析器类。相反,您可以只拥有一个 Parser 类,然后调用如下方法:

      ContactList contactList = parser.parse(jsonObject, ContactList.class);
      

      【讨论】:

      • 这看起来是一个非常有趣的方法,但在这样做之前我必须了解注入,)谢谢你的回答!
      • @Oscar:您无需担心注入方面。只需使用反射来实例化您作为参数给出的类型的对象。 (当然,这是假设该类型具有“默认”(无参数)构造函数。)关键是方法签名的设置方式使您不必进行任何转换。它使用泛型,应该可以帮助您消除当前策略使用的大量样板式代码。
      • 嗨,我不知道我是否遗漏了什么。在我的 JSON 类(readObjectFromUrl 方法)中,我将调用 Parser.parser 方法。目前我在 readObjectFromUrl 中收到一个解析器参数,这个解析器返回预期的对象类型。非常抱歉,但我看不出这种变化会带来多大的不同,我想我不理解你
      • @Oscar:您当前的解决方案要求您为每种类型的对象创建一个新的 Parser 实现(例如ContactListParser)。此解析器的代码似乎只是创建对象的一个​​实例 (new ContactList()),调用其他一些“解析”方法,然后返回该对象。然而,所有这三个步骤都可以通用地完成,使用反射来构造对象。因此,您可以避免为每种类型编写不同的实现。也许我误解了,您的“解析”方法只是挥手示意您将在那里编写一堆其他代码?
      • @Oscar:google 的gson 库符合我的描述。在此处查看示例:(sites.google.com/site/gson/gson-user-guide#TOC-Object-Examples)。您是否考虑过使用它,而不是为每种对象类型编写自己的自定义解析实现?
      猜你喜欢
      • 2011-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-01
      • 1970-01-01
      相关资源
      最近更新 更多