用于在Java

时间:2018-04-06 21:03:09

标签: java android generics interface static

我有一个Java类Model,它可以模拟远程数据库中的一些数据。我希望我的项目中的所有数据模型都能够从Map<String, Object>实例提供构建器(实际上,我正在使用Firestore使用SnapshotParser<Model>解析器,但我只需要调用{{1在每个模型中)。这应该类似于:

getData()

请注意,我将提供多个模型(public class Model { private String name; public Model(String name) { this.name = name; } public static SnapshotParser<Model> getDocParser() { return docSnapshot -> { Map<String, Object> data = docSnapshot.getData(); return new Model(data.getOrDefault("name", "John Doe")); }; } } Model2 ...),这些模型也需要提供此类接口。为了强制执行此行为,我为我的模型类创建了一个Model3泛型类来实现:

DocParserSupplier

这不起作用有两个原因(因为Android Studio告诉我):

  • public interface DocParserSupplier<T> { static SnapshotParser<T> getDocParser(); } 接口方法必须具有默认实现。如果不知道static,我就无法做到。
  • 我得到“T无法在静态上下文中引用”错误。

如果从上面的界面中删除T关键字,我可以做我想要的但是需要我创建一个static的实际实例来获取解析器。如果方法是静态的,它会更有意义。

有没有Java方法可以做我想要的事情?

编辑:我的具体用例是将Model匹配到我的数据库中的文档。构造RecyclerView对象需要解析器将键值数据转换为FirestoreRecyclerOptions

Model

2 个答案:

答案 0 :(得分:1)

接口强制执行实例的行为,因此可以以类型安全的方式传递对具有该行为的任何对象的引用。另一方面,静态方法不属于对象的任何特定实例;类名实际上只是一个名称空间。如果要强制执行行为,则必须在某处创建实例(或者如果绝对需要确保类具有特定的静态方法,则使用反射)。

除非这个系统要开放用于扩展,否则其他人可以定义他们自己的模型,我会说完全抛弃DocParserSupplier接口并完全像现在一样调用静态方法,或者将它们分解为工厂接口+实施。工厂选项很好,因为您可以使用返回虚拟解析器进行测试的虚假实现替换生产实现。

修改: Doc Parser Factory

List<List<Double>>

...

public interface DocParserFactory {
    SnapshotParser<Model1> getModel1Parser();
    SnapshotParser<Model2> getModel2Parser();
    ...
    SnapshotParser<Model1> getModelNParser();
}

...

// The implementation of each getModelXParser method
class DocParserFactoryImpl {

    SnapshotParser<Model1> getModel1Parser() {
        return docSnapshot -> {
            Map<String, Object> data = docSnapshot.getData();
            return new Model(data.getOrDefault("name", "John Doe"))};
    }

    ...

}

答案 1 :(得分:0)

与静态或非静态无关,因为您无法以这种或那种方式传递类型参数而无法创建通用对象的实例。事实上,几天前我回答了一个类似的问题,当时有人想使用枚举来获得所需的构建器。

简而言之,您不能在不以某种形式传递<T extends AbstractBuilder> T builder(final SomeNonGenericObject object)的情况下编写方法<T extends AbstractBuilder> T builder()(或者,在这种情况下,T)。即使它在运行时有意义,但如果你不告诉它是哪一种,编译器也无法弄清楚要使用哪种泛型类型。

在Java 8中,您可以使用方法引用来优雅地解决此问题。我对Android知之甚少,但我相信你还在使用Java 6,所以这不行。

无论如何,您可以拥有以下内容:

public <T extends AbstractBuilder> T builder(final Supplier<T> object) {
    return supplier.get();
}

final Supplier<AbstractBuilder> model1BuilderSupplier = Model1Builder::new;
builder(model1BuilerSupplier)
    .setQuery(query1, Model1.getDocParser())
    .build();

这不完全是你想要的,但是你试图去做的方式是行不通的。

相关问题