Dagger 2 - 提供的对象需要来自目标方法的实例
Dagger 2 - Provided object need instance from the target method
我需要在 dagger 2 中提供 TimeStamp
到 deserialize
的 JsonDeserializer
方法。
@Singleton
@Provides
public JsonDeserializer provideJsonDeserializer() {
return new JsonDeserializer() {
public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return new Timestamp(json.getAsJsonPrimitive().getAsLong());
}
};
}
但该对象需要来自 JsonDeserializer
的 JsonElement
个对象。我如何将该对象传递给我的 provideTimestamp
方法。
@Singleton
@Provides
public Timestamp provideTimestamp() {
}
或者我不应该通过 dagger 注入 Timestamp
,如果是这样,有人可以解释为什么,这可能有助于我了解更多关于 dagger 2 的信息。
您在第一个代码示例中使用它的方式是正确的,我会如何使用它:您应该调用 new Timestamp(...)
,而不是遵从 Dagger。
您应该区分的是 injectables 与 newables:图中的哪些对象应该被注入,哪些对象应该使用 new
创建?可能会认为每次调用 new
都是不好的,因为它降低了灵活性,但事实是它更像是一个判断调用:
- 如果您想要更改或替换实现,即使是通过在测试中使用测试替身或模拟,那么您的对象应该是可注入。对于不确定的或昂贵的对象尤其如此,因为您可能希望您的测试快速且确定。
- 如果实现 "value objects" 只是携带结构化数据,那么它们不太可能被替代,并且可能 可更新。
- 如果实现具有很少的依赖性并且易于创建,则它们可能是 可更新的。如果实现将大量服务作为构造函数参数(而不是许多数据值),那么它们可能应该是 injectable;这将是在测试中使用假货或模拟的一个很好的理由。
另请参阅: To “new” or not to “new”…,作者:Miško Hevery
如上所述,Timestamp 是一个值对象:您不太可能想要替换实现,Timestamp 除了每个实例数据外没有依赖项,而且实现非常容易创建。这使得 Timestamp 非常适合成为 newable.
在你的情况下,你还有一个额外的问题:你的新时间戳将根据你传入的 json
对象而变化,并且 json
对象将变化得足够多以至于它你不太可能想把它放在你的匕首图中。这意味着如果您 did 想要进行注入,而不是注入时间戳,您可能想要注入一个 TimestampFactory,它可能是 constructor reference, an AutoFactory 创建的实现,或者任何其他实现:
interface TimestampFactory {
Timestamp create(long value);
}
这似乎过分了,但是让我们假装 而不是您想要 Timestamp2,它还记录一天中的当前时间,因此可能会使测试变得困难。在这种情况下,您可以注入 timestamp factory:
@Singleton
@Provides
public JsonDeserializer provideJsonDeserializer(Timestamp2Factory tsFactory) {
return new JsonDeserializer() {
public Timestamp2 deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return tsFactory.create(json.getAsJsonPrimitive().getAsLong());
}
};
}
@Reusable
@Provides
public Timestamp2Factory provideTimestamp2Factory() {
// Merge in other parameters and dependencies if needed,
// but Timestamp2 only needs one value that create(long) supplies.
return Timestamp2::new;
// or, pre-Java-8:
return new Timestamp2Factory() {
@Override public Timestamp2 create(long time) {
return new Timestamp2(time);
}
}
}
这将允许您在测试中调用 provideJsonDeserializer
并传入您选择的 TimestampFactory,例如使用假系统时间而不是真实系统时间的时间戳工厂。这将使您的测试更加安全和确定。
但是,由于您想要快速、确定性的值对象 Timestamp,它没有外部依赖项,例如 RPC 服务、文件系统访问或实际系统时间,因此请保持您的 new Timestamp
调用问题。
我需要在 dagger 2 中提供 TimeStamp
到 deserialize
的 JsonDeserializer
方法。
@Singleton
@Provides
public JsonDeserializer provideJsonDeserializer() {
return new JsonDeserializer() {
public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return new Timestamp(json.getAsJsonPrimitive().getAsLong());
}
};
}
但该对象需要来自 JsonDeserializer
的 JsonElement
个对象。我如何将该对象传递给我的 provideTimestamp
方法。
@Singleton
@Provides
public Timestamp provideTimestamp() {
}
或者我不应该通过 dagger 注入 Timestamp
,如果是这样,有人可以解释为什么,这可能有助于我了解更多关于 dagger 2 的信息。
您在第一个代码示例中使用它的方式是正确的,我会如何使用它:您应该调用 new Timestamp(...)
,而不是遵从 Dagger。
您应该区分的是 injectables 与 newables:图中的哪些对象应该被注入,哪些对象应该使用 new
创建?可能会认为每次调用 new
都是不好的,因为它降低了灵活性,但事实是它更像是一个判断调用:
- 如果您想要更改或替换实现,即使是通过在测试中使用测试替身或模拟,那么您的对象应该是可注入。对于不确定的或昂贵的对象尤其如此,因为您可能希望您的测试快速且确定。
- 如果实现 "value objects" 只是携带结构化数据,那么它们不太可能被替代,并且可能 可更新。
- 如果实现具有很少的依赖性并且易于创建,则它们可能是 可更新的。如果实现将大量服务作为构造函数参数(而不是许多数据值),那么它们可能应该是 injectable;这将是在测试中使用假货或模拟的一个很好的理由。
另请参阅: To “new” or not to “new”…,作者:Miško Hevery
如上所述,Timestamp 是一个值对象:您不太可能想要替换实现,Timestamp 除了每个实例数据外没有依赖项,而且实现非常容易创建。这使得 Timestamp 非常适合成为 newable.
在你的情况下,你还有一个额外的问题:你的新时间戳将根据你传入的 json
对象而变化,并且 json
对象将变化得足够多以至于它你不太可能想把它放在你的匕首图中。这意味着如果您 did 想要进行注入,而不是注入时间戳,您可能想要注入一个 TimestampFactory,它可能是 constructor reference, an AutoFactory 创建的实现,或者任何其他实现:
interface TimestampFactory {
Timestamp create(long value);
}
这似乎过分了,但是让我们假装 而不是您想要 Timestamp2,它还记录一天中的当前时间,因此可能会使测试变得困难。在这种情况下,您可以注入 timestamp factory:
@Singleton
@Provides
public JsonDeserializer provideJsonDeserializer(Timestamp2Factory tsFactory) {
return new JsonDeserializer() {
public Timestamp2 deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return tsFactory.create(json.getAsJsonPrimitive().getAsLong());
}
};
}
@Reusable
@Provides
public Timestamp2Factory provideTimestamp2Factory() {
// Merge in other parameters and dependencies if needed,
// but Timestamp2 only needs one value that create(long) supplies.
return Timestamp2::new;
// or, pre-Java-8:
return new Timestamp2Factory() {
@Override public Timestamp2 create(long time) {
return new Timestamp2(time);
}
}
}
这将允许您在测试中调用 provideJsonDeserializer
并传入您选择的 TimestampFactory,例如使用假系统时间而不是真实系统时间的时间戳工厂。这将使您的测试更加安全和确定。
但是,由于您想要快速、确定性的值对象 Timestamp,它没有外部依赖项,例如 RPC 服务、文件系统访问或实际系统时间,因此请保持您的 new Timestamp
调用问题。