Вставить массив объектов в Guice - PullRequest
13 голосов
/ 26 февраля 2009

Я бы хотел добиться чего-то похожего в Guice:

public MyClass {

    private final InjectedObject[] injectedObjects;

    @Inject
    public MyClass(InjectedObject[] injectedObjects) {
        this.injectedObjects=injectedObjects;
    }
}

т.е. я хотел бы иметь возможность создавать определенное количество экземпляров объекта и вставлять их в другой объект в виде массива. Я мог бы сделать это вместо этого:

public MyClass {

    private final InjectedObject[] injectedObjects;

    @Inject
    public MyClass(InjectedObjectProvider injectedObjectProvider) {
        this.injectedObjects=injectedObjectProvider.getArrayOfInjectedObjects(5);
    }
}

... но мне было интересно, есть ли другой маршрут, который был бы более элегантным?

Ответы [ 4 ]

16 голосов
/ 18 декабря 2009

Не уверен, что это соответствует вашим потребностям, но Multibindings сработало для меня, когда мне нужно было ввести несколько элементов одного вида (хотя это дает набор).

8 голосов
/ 25 апреля 2009

Один из вариантов - добавить Provider<InjectedObject> в ваш класс, как сказал Джесси:

public class MyClass {
  private final List<InjectedObject> injectedObjects;

  @Inject
  public MyClass(Provider<InjectedObject> injectedObjectProvider) {
    List<InjectedObject> objects = new ArrayList<InjectedObject>();
    for (int i = 0; i < 5; i++) {
      objects.add(injectedObjectProvider.get());
    }
    injectedObjects = Collections.unmodifiableList(objects);
  }
}

Это может быть проблематично. Если InjectedObject определено как @Singleton или @RequestScoped, то каждый раз, когда вы звоните injectedObjectProvider.get(), вы получаете одну и ту же ссылку. Другая проблема с введением Provider для этого состоит в том, что из API не будет ясно, что MyClass зависит от нескольких экземпляров InjectedObject. Наконец, вы в MyClass жестко запрограммировали, что его нужно ввести пятью экземплярами.

Редко, когда вам нужно будет ввести Provider в объект. Обычно, когда я делаю это, это потому, что область действия текущего объекта означает, что он будет более долгоживущим, чем область действия зависимого объекта (например, @Singleton, которому требуется доступ к @RequestScoped объекту).

Вместо внедрения Provider вы можете вставить List<InjectedObject> в конструктор и создать метод провайдера в модуле Guice:

@Provides
MyClass prividesMyClass(Provider<InjectedObject> injectedObjectProvider) {
  List<InjectedObject> objects = new ArrayList<InjectedObject>();
  for (int i = 0; i < 5; i++) {
   objects.add(injectedObjectProvider.get());
  }
  return new MyClass(objects);
}

(конечно, вы можете связать, используя TypeLiteral)

Почему это лучше? Несмотря на то, что вы все еще жестко кодируете пять объектов в этом коде, он не жестко запрограммирован в MyClass, поэтому клиенты MyClass (включая тесты для самого MyClass) могут выбрать конструирование объекта в другом пути.

Если жесткое программирование этих знаний в модуле Guice не является хорошей идеей, вместо этого вы можете создать интерфейс с более конкретным контрактом, чем Provider

public interface InjectedObjectRepository {
  List<InjectedObject> getInjectedObjects();
}

Даже если вы решите, что вы хотите, чтобы MyClass отвечал за знание количества создаваемых экземпляров, вы можете захотеть создать интерфейс (возможно, с именем InjectedObjectSupplier, чтобы вы могли явно задокументировать, что каждый раз вы ожидаете уникальный экземпляр) .

8 голосов
/ 27 февраля 2009

Мне любопытно, почему вы хотите, чтобы несколько объектов создавались с нетерпением. Вы можете успешно ввести Provider<InjectedObject> и вызывать Provider.get() каждый раз, когда вам нужен экземпляр. Если вам действительно нужно 5, вы можете собрать их в цикле:

public MyClass {
  private final List<InjectedObject> injectedObjects;

  @Inject
  public MyClass(Provider<InjectedObject> injectedObjectProvider) {
    injectedObjects = new ArrayList<InjectedObject>();
    for (int i = 0; i < 5; i++) {
      injectedObjects.add(injectedObjectProvider.get());
    }
  }
}
1 голос
/ 18 апреля 2012

Добавление этого ответа, чтобы люди знали, как внедрить массив, так как это сначала появляется в поиске Google. Я считаю, что любой из них будет работать:

В настройках модуля: bind(InjectedObject[].class).toInstance(someArray); или как метод Провайдера:

@Provides
InjectedObject[] getInjectedObject(@Inject Provider<InjectedObject> provider) {
  InjectedObject[] objects = new InjectedObject[5];
  for (int i = 0; i < objects.length; i++) {
    objects[i] = provider.get();
  }
}
...