因此,我目前正在重新设计我的Android应用程序以使用Dagger。我的应用程序很大且很复杂,最近遇到了以下情况:
对象A需要一个特殊的DebugLogger实例,该实例非常适合注入(inject)。无需绕过记录器,我可以通过A的构造函数将其注入(inject)。看起来像这样:
class A
{
private DebugLogger logger;
@Inject
public A(DebugLogger logger)
{
this.logger = logger;
}
// Additional methods of A follow, etc.
}
到目前为止,这是有道理的。但是,A必须由另一个类B构造。必须构造A的多个实例,因此按照Dagger的处理方式,我简单地将
Provider<A>
注入(inject)到B中:class B
{
private Provider<A> aFactory;
@Inject
public B(Provider<A> aFactory)
{
this.aFactory = aFactory;
}
}
好的,到目前为止很好。但是,等等,突然之间,A需要额外的输入,例如对其构造至关重要的称为“金额”的整数。现在,我的A构造函数应如下所示:
@Inject
public A(DebugLogger logger, int amount)
{
...
}
突然,这个新参数会干扰注入(inject)。而且,即使这样做确实可行,除非我弄错了,否则在从提供者那里获取新实例时,我也无法传递“金额”。我在这里可以做几件事,但我的问题是哪一个是最好的?
我可以通过添加一个预期在构造函数之后调用的
setAmount()
方法来重构A。但是,这很丑陋,因为它迫使我延迟A的构造,直到填写了“金额”。如果我有两个这样的参数,“金额”和“频率”,那么我将有两个 setter ,这将意味着复杂的检查,以确保在调用两个setter之后恢复A的构造,否则我将不得不在混合中添加第三个方法,如下所示:(Somewhere in B):
A inst = aFactory.get();
inst.setAmount(5);
inst.setFrequency(7);
inst.doConstructionThatRequiresAmountAndFrequency();
另一种选择是,我不使用基于构造函数的注入(inject),而使用基于字段的注入(inject)。但是现在,我必须公开我的 Realm 。这对我来说不合适,因为现在我有义务向其他类(class)公开类(class)的内部数据。
到目前为止,我能想到的唯一优雅的解决方案是为提供程序使用基于字段的注入(inject),如下所示:
class A
{
@Inject
public Provider<DebugLogger> loggerProvider;
private DebugLogger logger;
public A(int amount, int frequency)
{
logger = loggerProvider.get();
// Do fancy things with amount and frequency here
...
}
}
即使如此,我也不确定时间,因为我不确定Dagger是否会在调用构造函数之前注入(inject)提供程序。
有没有更好的办法?我是否只是缺少有关Dagger工作原理的信息?
最佳答案
您所说的被称为辅助注入(inject),Dagger当前不以任何自动方式提供支持。
您可以使用工厂模式解决此问题:
class AFactory {
@Inject DebugLogger debuggLogger;
public A create(int amount, int frequency) {
return new A(debuggLogger, amount);
}
}
现在,您可以注入(inject)这个工厂,并使用它来创建
A
的实例:class B {
@Inject AFactory aFactory;
//...
}
当您需要使用“数量”和“频率”创建
A
时,请使用工厂。A a = aFactory.create(amount, frequency);
这允许
A
具有记录器,数量和频率字段的final
实例,同时仍使用注入(inject)来提供记录器实例。Guice有一个辅助注入(inject)插件,该插件实质上为您自动创建了这些工厂。在Dagger邮件列表上有have been discussion,其中包含添加它们的适当方法,但在撰写本文时尚未确定。