用于在Java中实施通用静态方法的接口
我有一个Java类用于在Java中实施通用静态方法的接口,java,android,generics,interface,static,Java,Android,Generics,Interface,Static,我有一个Java类Model,它对远程数据库中的一些数据进行建模。我希望我的项目中的所有数据模型都能够从Map实例提供一个构建器(实际上,我正在使用Firestore的SnapshotParser解析器,但我只需要在每个模型中调用getData())。这应该类似于: public class Model { private String name; public Model(String name) { this.name = name; } public static
Model
,它对远程数据库中的一些数据进行建模。我希望我的项目中的所有数据模型都能够从Map
实例提供一个构建器(实际上,我正在使用Firestore的SnapshotParser
解析器,但我只需要在每个模型中调用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"));
};
}
}
这不起作用有两个原因(Android Studio告诉我):
接口方法必须具有默认实现。如果不知道静态
,我就不能那样做t
- 我得到了“
无法在静态上下文中引用”错误T
static
关键字,我可以做我想做的事情,但这需要我创建模型的实际实例来获取解析器。它会起作用,但如果方法是静态的,则更有意义
有没有一种Java方法可以实现我想要的功能
编辑:我的特定用例与数据库中的文档相匹配。构建FirestoreRecyclerOptions
对象需要解析器将键值数据转换为模型
:
FirestoreRecyclerOptions<Model1> fro1 = new FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, Model1.getDocParser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, Model2.getDocParser())
.build();
FirestoreRecyclerOptions fro1=新建FirestoreRecyclerOptions.Builder()
.setQuery(query1,Model1.getDocParser())
.build();
FirestoreRecyclerOptions fro2=新建FirestoreRecyclerOptions.Builder()
.setQuery(query2,Model2.getDocParser())
.build();
这与静态或非静态无关,而是与这样一个事实有关,即如果不以某种方式传递类型参数,就无法创建泛型对象的实例。事实上,几天前我回答了一个类似的问题,当时有人想使用enum获得所需的生成器
简而言之,如果不以某种形式传递T
,则无法编写方法T builder(最终SomeNonGenericObject对象)
(或者在本例中,T builder()
)。即使它在运行时是有意义的,但如果您不告诉编译器它是哪种泛型类型,编译器也无法确定要使用哪种泛型类型
在Java8中,您可以通过方法引用优雅地解决这个问题。我对Android不太了解,但我相信您仍然使用Java6,所以这不起作用
无论如何,您可以有如下内容:
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();
公共T生成器(最终供应商对象){
返回供应商。get();
}
最终供应商model1BuilderSupplier=Model1Builder::new;
建筑商(1型建筑商供应商)
.setQuery(query1,Model1.getDocParser())
.build();
这并不完全是您想要的,但您尝试的方式将不起作用。接口强制执行实例的行为,以便可以以类型安全的方式传递对具有该行为的任何对象的引用。另一方面,静态方法不属于对象的任何特定实例;类名本质上只是一个名称空间。如果您想要强制执行行为,您必须在某处创建一个实例(或者使用反射,如果绝对需要确保类具有特定的静态方法)
除非这个系统将被扩展,其他人可以定义他们自己的模型,否则我要说的是完全抛弃DocParserSupplier接口,完全按照您现在的方式调用静态方法,或者将它们分解到工厂接口+实现中。factory选项很好,因为您可以用返回虚拟解析器进行测试的伪实现替换生产实现
编辑:文档解析器工厂
public interface DocParserFactory {
SnapshotParser<Model1> getModel1Parser();
SnapshotParser<Model2> getModel2Parser();
...
SnapshotParser<Model1> getModelNParser();
}
公共接口DocParserFactory{
SnapshotParser getModel1Parser();
SnapshotParser getModel2Parser();
...
SnapshotParser getModelNParser();
}
//每个getModelXParser方法的实现
类DocParserFactoryImpl{
SnapshotParser getModel1Parser(){
返回docSnapshot->{
Map data=docSnapshot.getData();
返回新模型(data.getOrDefault(“name”,“johndoe”))};
}
...
}
私有DocParserFactory DocParserFactory;
//您可以注入真实实例(DocParserFactoryImpl)或
//返回具有可预测结果的虚拟解析器的测试实例
//当您构造此对象时。
公共ThisObject(DocParserFactory DocParserFactory){
this.docParserFactory=docParserFactory;
}
...
//你的代码
公共方法(){
...
FirestoreRecyclerOptions fro1=新建
FirestoreRecyclerOptions.Builder()
.setQuery(query1,docParserFactory.getModel1Parser())
.build();
FirestoreRecyclerOptions fro2=新建
FirestoreRecyclerOptions.Builder()
.setQuery(query2,docParserFactory.getModel2Parser())
.build();
...
}
@mszymborski静态
方法允许在以Java SE 8开始的接口中使用。它们只是没有被子类型继承。可能有两件事是重复的——既然你提到了Android Studio,我就在这里加上Android标签。第二:为什么需要将其作为静态方法?这有一种味道,因为您可能希望有一些具体定义的方法,因为您希望每种解析器类型的方法不同。您需要实例方法来对对象强制执行某些行为。@Makoto解析器的行为取决于类本身,而不是实例;我不需要它是静态的,但在我的用例中,我需要解析器,而不需要模型的实际实例@Bhesh Gurung我不明白你的评论,你能为你描述的模式举个小例子吗?以及它们如何应用于我当前的场景?我不熟悉你描述的概念。我用一个工厂示例编辑了上面的答案。我可以在接口中声明静态方法,所以我认为我使用的是Java8
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"))};
}
...
}
private DocParserFactory docParserFactory;
// You can inject either the real instance (DocParserFactoryImpl) or a
// test instance which returns dummy parsers with predicable results
// when you construct this object.
public ThisObject(DocParserFactory docParserFactory) {
this.docParserFactory = docParserFactory;
}
...
// Your code
public void someMethod() {
...
FirestoreRecyclerOptions<Model1> fro1 = new
FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, docParserFactory.getModel1Parser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new
FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, docParserFactory.getModel2Parser())
.build();
...
}