使用Dagger对构造函数进行依赖注入 [英] Using Dagger for dependency injection on constructors

查看:85
本文介绍了使用Dagger对构造函数进行依赖注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我目前正在重新设计我的Android应用程序,以使用 Dagger 。我的应用程序又大又复杂,最近遇到了以下情况:

So, I'm currently redesigning an Android app of mine to use Dagger. My app is large and complicated, and I recently came across the following scenario:

对象A需要一个特殊的DebugLogger实例,该实例非常适合注入。无需绕过记录器,我可以通过A的构造函数将其注入。看起来像这样:

Object A requires a special DebugLogger instance which is a perfect candidate for injection. Instead of passing around the logger I can just inject it through A's constructor. This looks something like this:

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> 注入B:

So far this makes sense. However, A needs to be constructed by another class B. Multiple instances of A must be constructed, so following Dagger's way of doing things, I simple inject a Provider<A> into B:

class B
{
    private Provider<A> aFactory;

    @Inject
    public B(Provider<A> aFactory)
    {
        this.aFactory = aFactory;
    }
}

好的,到目前为止。但是,等等,突然之间,A需要额外的输入,例如对其构造至关重要的称为金额的整数。现在,我的A构造函数应如下所示:

Ok, good so far. But wait, suddenly A needs additional inputs, such as an integer called "amount" that is vital to its construction. Now, my constructor for A needs to look like this:

@Inject
public A(DebugLogger logger, int amount)
{
...
}

突然之间,这个新东西参数会干扰注入。而且,即使这样做确实可行,除非我弄错了,否则在从提供者那里获取新实例时,我也无法传递金额。我可以在这里做几件事,而我的问题是哪一个是最好的?

Suddenly this new parameter interferes with injection. Moreover, even if this did work, there would be no way for me to pass in "amount" when retrieving a new instance from the provider, unless I am mistaken. There's several things I could do here, and my question is which one is the best?

我可以通过添加 setAmount()方法,预期在构造函数之后调用。但是,这很丑陋,因为它迫使我延迟A的构造,直到填写了金额。如果我有两个这样的参数,金额和频率,那么我将有两个设置器,这意味着复杂的检查以确保在调用两个设置器之后恢复A的构造,否则我将不得不在混合中添加第三个方法,例如:

I could refactor A by adding a setAmount() method that is expected to be called after the constructor. This is ugly, however, because it forces me to delay construction of A until "amount" has been filled in. If I had two such parameters, "amount" and "frequency", then I would have two setters, which would mean either complicated checking to ensure that construction of A resumes after both setters are called, or I would have to add yet a third method into the mix, like so:

(Somewhere in B):

A inst = aFactory.get();
inst.setAmount(5);
inst.setFrequency(7);
inst.doConstructionThatRequiresAmountAndFrequency();

另一种选择是我不使用基于构造函数的注入,而使用基于字段的注入。但是现在,我必须公开我的领域。这对我来说不合适,因为现在我有义务向其他班级透露班级的内部数据。

The other alternative is that I don't use constructor-based injection and go with field-based injection. But now, I have to make my fields public. This doesn't sit well with me, because now I am obligated to reveal internal data of my classes to other classes.

到目前为止,我可以做的唯一优雅的解决方案想到的是对提供商使用基于字段的注入,例如:

So far, the only somewhat elegant solution I can think of is to use field-based injection for providers, like so:

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是否会在调用构造函数之前注入提供程序。

Even still, I'm unsure about the timing, since I'm not sure if Dagger will inject the provider before my constructor is called.

有更好的方法吗?我只是想了解Dagger的工作原理吗?

Is there a better way? Am I just missing something about how Dagger works?

推荐答案

您在说的被称为辅助注射,目前尚不支持

What you are talking about is known as assisted injection and is not currently supported by Dagger in any automatic fashion.

您可以使用工厂模式来解决此问题:

You can work around this with the factory pattern:

class AFactory {
  @Inject DebugLogger debuggLogger;

  public A create(int amount, int frequency) {
    return new A(debuggLogger, amount);
  }
}

现在您可以注入该工厂并使用它来创建 A 的实例:

Now you can inject this factory and use it to create instances of A:

class B {
  @Inject AFactory aFactory;

  //...
}

需要使用工厂的'金额'和'频率'创建 A

and when you need to create an A with your 'amount' and 'frequency' you use the factory.

A a = aFactory.create(amount, frequency);

这允许 A 具有 final 记录器,金额和频率字段的实例,同时仍使用注入来提供记录器实例。

This allows for A to have final instances of the logger, amount, and frequency fields while still using injection to provide the logger instance.

Guice有一个辅助注射插件,从本质上为您自动创建这些工厂。在Dagger邮件列表中,已经已进行了讨论,介绍了适合他们使用的方法被添加,但在撰写本文时尚未决定。

Guice has an assisted injection plugin which essentially automates the creation of these factories for you. There have been discussion on the Dagger mailing list about the appropriate way for them to be added but nothing has been decided upon as of this writing.

这篇关于使用Dagger对构造函数进行依赖注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆