2009-02-26 4 views
12

Я хотел бы добиться чего-то, похожее на следующий 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); 
    } 
} 

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

ответ

8

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

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()); 
    } 
    } 
} 
+0

Спасибо за предложение - причины, имеющие несколько при условии, жадность, чтобы иметь возможность разместить их в ThreadPool - количество экземпляров в пуле будет зависеть от количества доступных ядер. – Rich

+0

Как бы вы это сделали, если у вас не было контроля над исходным кодом MyClass, но просто хотелось вставить его с помощью привязок и другого кода в конфигурацию модуля (желательно, не используя Multibindings, поскольку это еще не совместимо с Gin)? – Snekse

+0

Snekse, вы можете создать метод @Provides, который принимает Поставщик как параметр и вызывает конструктор MyClass в конце. –

8

Одним из вариантов было бы придать Provider<InjectedObject> в своем классе, как уже упоминалось Jesse:

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, чтобы вы могли явно указывать, что каждый раз вы ожидаете уникального экземпляра.

+0

Мне нравится этот ответ, но как бы вы это сделали, если бы вы хотели, чтобы каждый из 5 'InjectedObject' был другим имплантом, управляемым Guice? Пример: 'связывания (InjectedObject.class) .annotatedWith (AnnotA.class) .to (ImplA.class) .в (Singleton.class);' ' связывания (InjectedObject.class) .annotatedWith (AnnotB.class) .to (ImplB.class) .in (Singleton.class); ' – Snekse

+0

@Snekse. Вы можете делать то, что хотите, с помощью метода поставщика (метод, аннотированный с помощью' @ Provides'). – NamshubWriter

+0

Просто так я понятен, вы имеете в виду 5 методов? 'обеспечиватьImplA()', 'обеспечиватьImplB()' и т. д. ???? – Snekse

15

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

+0

Многомножества производят наборы, которые упорядочены (итерация по элементам такая же, как элементы порядка привязаны к Multibinder). Это означает, что наборы, созданные Multibinding, часто так же хороши, как List или массив. –

1

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^