Использование Dagger для внедрения зависимостей в конструкторы
Итак, я в настоящее время переделываю свое приложение для Android, чтобы использоватьКинжал, Мое приложение большое и сложное, и недавно я столкнулся со следующим сценарием:
Объект A требует специального экземпляра DebugLogger, который является идеальным кандидатом для внедрения. Вместо того, чтобы обойти регистратор, я могу просто вставить его через конструктор А. Это выглядит примерно так:
class A
{
private DebugLogger logger;
@Inject
public A(DebugLogger logger)
{
this.logger = logger;
}
// Additional methods of A follow, etc.
}
Пока это имеет смысл. Тем не менее, A должен быть создан другим классом B. Несколько экземпляров A должны быть созданы, поэтому, следуя способу Даггера, я просто внедряюProvider<A>
в Б:
class B
{
private Provider<A> aFactory;
@Inject
public B(Provider<A> aFactory)
{
this.aFactory = aFactory;
}
}
Хорошо, пока хорошо. Но подождите, внезапно A потребуются дополнительные входные данные, такие как целое число, называемое «количество», которое жизненно важно для его построения. Теперь мой конструктор для A должен выглядеть так:
@Inject
public A(DebugLogger logger, int amount)
{
...
}
Внезапно этот новый параметр мешает инъекции. Более того, даже если бы это сработало, у меня не было бы возможности передать «сумму» при получении нового экземпляра у провайдера, если я не ошибаюсь. Здесь я мог бы сделать несколько вещей, и мой вопрос: какой из них лучший?
Я мог бы рефакторинг А, добавивsetAmount()
метод, который, как ожидается, будет вызван после конструктора. Однако это уродливо, потому что заставляет меня откладывать построение A до тех пор, пока не будет заполнено «количество». Если бы у меня было два таких параметра, «количество» и «частота», то у меня было бы два сеттера, что означало бы либо сложная проверка, чтобы убедиться, что конструкция A возобновляется после вызова обоих сеттеров, или мне пришлось бы добавить еще один третий метод в микс, например так:
(Somewhere in B):
A inst = aFactory.get();
inst.setAmount(5);
inst.setFrequency(7);
inst.doConstructionThatRequiresAmountAndFrequency();
Другой альтернативой является то, что я не использую инъекцию на основе конструктора и использую инъекцию на основе поля. Но теперь я должен обнародовать свои поля. Это не устраивает меня, потому что теперь я обязан раскрывать внутренние данные своих классов другим классам.
Пока что единственное элегантное решение, о котором я могу подумать, - это использовать инъекцию на основе поля для поставщиков, например:
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 вводить провайдер до вызова моего конструктора.
Есть ли способ лучше? Я что-то упускаю из-за того, как работает Dagger?