Внедрить массив объектов в Guice
В 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);
}
}
... но мне было интересно, был ли другой маршрут более элегантным?
Ответы
Ответ 1
Мне любопытно, почему вы хотите, чтобы несколько объектов создавались с нетерпением. Возможно, вам удастся внедрить 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());
}
}
}
Ответ 2
Не уверен, что это соответствует вашим потребностям, но Multibindings работал у меня, когда мне нужно было вводить несколько элементов одного типа (это производит набор, хотя).
Ответ 3
Одним из вариантов было бы ввести 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
), чтобы вы могли явно указывать, что каждый раз вы ожидаете уникальный экземпляр.
Ответ 4
Добавление этого ответа, чтобы люди знали, как вводить массив, так как это первое при поиске в google. Я считаю, что любой из них будет работать:
В модуле configure:
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();
}
}