Guice AssistedInjection Factory с логикой - PullRequest
0 голосов
/ 08 июня 2018

Я использовал guice для проекта.

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

Демонстрационный код

@Singleton
public class MyFactory {

    private final Foo foo;

    @Inject
    public MyFactory(final Foo foo) {
        this.foo = foo;
    }

    public A create(final Bar bar) {
        switch (bar) {
            case 0:
                return new B(foo, bar);
            case 1:
                return new C(foo, bar);
            //this goes on
        }
    }
}

public abstract A {
    public A(final Bar bar) {
        //do sth
    }
}

public B extends A {
    private final Foo foo;

    public B(final Foo foo, final Bar bar) {
        super(bar);
        this.foo = foo;
    }
}

public C extends A {
    private final Foo foo;

    public C(final Foo foo, final Bar bar) {
        super(bar);
        this.foo = foo;
    }
}

Что я хочу знать, еслиЯ могу заменить фабрику на Guice для непосредственного внедрения реализаций A (обратите внимание, что они должны использовать вспомогательную инъекцию)?

Спасибо.

1 Ответ

0 голосов
/ 08 июня 2018

Вам все еще понадобится MyFactory , чтобы выбрать реализацию, основанную на id, хотя ваша вспомогательная инъекция может быть очень короткой .

// No need for this to be @Singleton;
// if you want the same shared Foo instance, make it @Singleton
public class MyFactory {

    private final B.Factory bFactory;
    private final C.Factory cFactory;

    @Inject
    public MyFactory(B.Factory bFactory, C.Factory cFactory) {
        this.bFactory = bFactory;
        this.cFactory = cFactory;
    }

    public A create(final Bar bar) {
        switch (bar.getSomeInteger()) {   // I assume you're checking a
                                          // property of bar
            case 0:
                return bFactory.create(bar);
            case 1:
                return cFactory.create(bar);
            //this goes on
        }
    }
}

public B extends A {
    public interface Factory {
        B create(Bar bar);
    }

    private final Foo foo;

    public B(final Foo foo, @Assisted final Bar bar) {
        super(bar);
        this.foo = foo;
    }
}

public C extends A {
    public interface Factory {
        C create(Bar bar);
    }

    private final Foo foo;

    public C(final Foo foo, @Assisted final Bar bar) {
        super(bar);
        this.foo = foo;
    }
}

ИВаш модуль:

public class YourModule extends AbstractModule {
  @Override public void configure() {
    install(new FactoryModuleBuilder().build(B.Factory.class));
    install(new FactoryModuleBuilder().build(C.Factory.class));
  }
}

Редактировать: Вы не нуждаетесь в вызове implement на FactoryModuleBuilder в моем примере, потому что B.Factory имеет create метод, который возвращает ваш подкласс B. Если вы хотите, чтобы метод возвращал ваш суперкласс A, скрывая конкретный тип, вы можете сделать это;тогда вам понадобится вызов implement, потому что Guice не будет знать, какой конструктор попытаться вызвать.

Если вы хотите заставить потребителей кодировать реализацию, вы можете обратиться к фабрике, котораятолько возвращает интерфейс.Как правило, было бы неплохо скрыть детали реализации , и, вероятно, потребуется создать A.Factory с методом A create(Bar bar) и связать его с implement.Однако здесь не нужно , потому что ваш MyFactory уже возвращает A и скрывает подкласс реализации (действующий как A.Factory с логикой), и потому что вам потребуется @Named или какая-либо другая аннотация квалификатора, чтобы различатьдве A.Factory привязки, которые вы создаете.Короче говоря, это дополнительное осложнение, не приносящее пользы в этом конкретном случае.

...