Dagger 2 - 提供的对象需要来自目标方法的实例

Dagger 2 - Provided object need instance from the target method

我需要在 dagger 2 中提供 TimeStampdeserializeJsonDeserializer 方法。

@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());
            }
        };
    }

但该对象需要来自 JsonDeserializerJsonElement 个对象。我如何将该对象传递给我的 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 调用问题。