Реализация по умолчанию с использованием кинжала, если @Named не найден - PullRequest
0 голосов
/ 23 мая 2018

Проблема, с которой я сталкиваюсь, заключается в том, что у меня есть базовый класс и несколько дочерних классов.Для разрешения конкретного дочернего класса я использую аннотацию @Named в Dagger 2. Что я пытаюсь добиться, это если я делаю инъекцию с @Named ("Child3"), а нет Предоставлять @Named ("Child3"), тогда я долженполучить экземпляр базового класса по умолчанию.

public class BaseClass {

public void haveFun(){
    System.out.print("Having fun base");
}

}

public class Child1 extends BaseClass {
@Override
public void haveFun() {
    System.out.print("Having fun Child1");
}
}

public class Child2 extends BaseClass {
@Override
public void haveFun() {
    System.out.print("Having fun Child2");
 }
}

Теперь в модуле я предоставляю такие объекты:

 @Provides
@Named("Child1")
static BaseClass provideChild1(){
    return new Child1();
}

@Provides
@Named("Child2")
static BaseClass provideChild2(){
    return new Child2();
}


@Provides
static BaseClass provideBaseClass(){
    return new BaseClass();
}

Теперь в своей деятельности я делаю инъекции так:

public class ReceiptActivity extends AppCompatActivity {

@Inject @Named("Child1") BaseClass child1;
@Inject @Named("Child2") BaseClass child2;
@Inject @Named("Child3") BaseClass child3;

Как@Named ("Child3") не предоставляется, поэтому есть ошибка времени компиляции, но я хочу, чтобы, если @Named ("Child3") не было, я должен получить экземпляр BaseClass.Как мне этого добиться?

1 Ответ

0 голосов
/ 25 мая 2018

К сожалению, квалифицированные привязки (привязки, использующие аннотации квалификаторов, такие как @Named), на самом деле не имеют запасной вариант или значение по умолчанию.Каждая привязка различна, и разные привязки не считаются связанными.Это затрудняет написание резервной логики, как вы просили.

Это также имеет смысл: @Named("Porsche") Engine и @Named("Lawnmower") Engine никогда не заменят друг друга, несмотря на общий базовый тип.Это совершенно разные зависимости, и если вам не хватает @Named("Porsche") Engine, Dagger следует политике, согласно которой он должен терпеть неудачу во время компиляции , а не искать несоответствующий или неквалифицированный Engine.

В отличие от этого, вы можете связать карту или использовать Multibindings , чтобы указать заменяемость или гибкость, которые вы ищете.Вместо внедрения самой привязки вы добавляете карту или фабрику, которая инкапсулирует карту и извлекает правильную привязку для вас.

// This uses Multibindings, but you could manually create a Map instead.

@Binds @IntoMap @StringKey("Child1")
abstract BaseClass provideChild1(Child1 child1);

@Binds @IntoMap @StringKey("Child2")
abstract BaseClass provideChild2(Child2 child2);

// Then in your consumer...

@Inject Map<String, BaseClass> mapOfBaseClasses;
@Inject BaseClass baseClass;

// Or make an injectable Factory:

public class YourClassFactory {
  private final Map<String, Provider<BaseClass>> baseClassMap;
  private final Provider<BaseClass> baseClassProvider;

  @Inject public YourClassFactory(/* ... */) { /* set fields */ }

  public BaseClass get(String key) { /* write fallback logic here */ }
}

Если у вас есть конкретная привязка, которая может присутствоватьили отсутствует, вы также можете использовать @BindsOptionalOf, чтобы указать, что привязка может отсутствовать во время компиляции, а затем вы можете обнаружить ее во время выполнения.

@BindsOptionalOf @Named("Child3")
abstract BaseClass provideOptionalOfChild3();

// Then in your consumer:

private final BaseClass baseClass;

@Inject public YourConsumer(
    @Named("Child3") Optional<BaseClass> optionalChild3,
    Provider<BaseClass> defaultBaseClass) {
  baseClass =
      optionalChild3.isPresent()
      ? optionalChild3.get()
      : defaultBaseClass.get();
}
...