2009-02-26 37 views
12

Tôi muốn đạt được một cái gì đó tương tự như sau trong Guice:Tiêm một mảng của các đối tượng trong Guice

public MyClass { 

    private final InjectedObject[] injectedObjects; 

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

tức là tôi muốn để có thể tạo ra một số lượng nhất định các trường hợp của một đối tượng, và tiêm chúng vào một đối tượng khác như một mảng. Thay vào đó, tôi có thể thực hiện việc này:

public MyClass { 

    private final InjectedObject[] injectedObjects; 

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

... nhưng tôi đã tự hỏi liệu có một tuyến đường thanh lịch hơn không?

Trả lời

8

Tôi rất tò mò vì sao bạn muốn một số đồ vật được tạo ra háo hức. Bạn có thể đã thành công khi tiêm Provider<InjectedObject> và gọi Provider.get() mỗi lần bạn cần một phiên bản. Nếu bạn thực sự cần 5, bạn có thể xây dựng 'em trong một vòng lặp:

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

Cảm ơn đã gợi ý - lý do có nhiều quy háo hức được để có thể đặt chúng vào một ThreadPool - số lượng các cá thể trong nhóm sẽ phụ thuộc vào số lượng lõi có sẵn. – Rich

+0

Bạn sẽ làm như thế nào nếu bạn không có quyền kiểm soát mã nguồn MyClass, nhưng chỉ muốn tiêm nó bằng cách sử dụng các ràng buộc và mã khác trong cấu hình Module (Tốt hơn là không sử dụng Multibindings vì nó không tương thích với Gin)? – Snekse

+0

Snekse, bạn có thể tạo phương thức @Provides lấy Nhà cung cấp làm tham số và gọi hàm dựng MyClass ở cuối. –

8

Một lựa chọn sẽ được tiêm một Provider<InjectedObject> vào lớp học của bạn, như Jesse nói:

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); 
    } 
} 

Việc làm này có thể có vấn đề . Nếu InjectedObject có phạm vi @Singleton hoặc @RequestScoped, thì mỗi lần bạn gọi injectedObjectProvider.get() bạn sẽ nhận được cùng một tham chiếu. Một vấn đề khác khi tiêm một Provider để làm điều này là nó sẽ không được rõ ràng từ API mà MyClass phụ thuộc vào nhiều trường hợp của InjectedObject. Cuối cùng, bạn đã hardcoded trong MyClass rằng nó cần phải được tiêm với năm trường hợp.

Rất hiếm khi bạn cần phải tiêm Provider vào một đối tượng. Thông thường khi tôi làm điều này, đó là vì phạm vi của đối tượng hiện tại có nghĩa là nó sẽ tồn tại lâu hơn phạm vi của đối tượng phụ thuộc (ví dụ: @Singleton cần truy cập đối tượng @RequestScoped).

Thay vì tiêm một Provider, bạn có thể tiêm một List<InjectedObject> vào constructor, và tạo ra một phương pháp cung cấp dịch vụ trong một module 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); 
} 

(bạn có thể, tất nhiên, ràng buộc sử dụng một TypeLiteral)

Tại sao điều này lại tốt hơn? Mặc dù bạn vẫn còn mã hóa cứng năm đối tượng trong mã này, nhưng nó không được mã hóa cứng trong MyClass, vì vậy các máy khách của MyClass (bao gồm các bài kiểm tra cho chính mình là MyClass) có thể chọn xây dựng đối tượng theo các cách khác nhau.

Nếu cứng mã hóa kiến ​​thức này trong một module Guice không phải là một ý tưởng tốt, bạn thay vì có thể tạo ra một giao diện mà có một hợp đồng cụ thể hơn Provider

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

Thậm chí nếu bạn quyết định rằng bạn muốn MyClass chịu trách nhiệm về việc biết có bao nhiêu trường hợp để tạo, bạn có thể muốn tạo một giao diện (có thể là InjectedObjectSupplier để bạn có thể ghi rõ ràng rằng bạn mong đợi một cá thể duy nhất mỗi lần.

+0

Tôi thích câu trả lời này, nhưng làm thế nào bạn sẽ làm được điều này nếu bạn muốn mỗi 5 'Tiêm của các mũi tên khác nhau được quản lý bởi Guice? Ví dụ: 'bind (InjectedObject.class) .annotatedWith (AnnotA.class) .to (ImplA.class) .in (Singleton.class);' 'bind (InjectedObject.class) .annotatedWith (AnnotB.class) .to (ImplB.class) .in (Singleton.class); ' – Snekse

+0

@Snekse Bạn có thể làm những gì bạn muốn với một phương pháp nhà cung cấp (một phương pháp được chú thích với' @ Provides') – NamshubWriter

+0

Chỉ cần vì vậy tôi rõ ràng, bạn có nghĩa là có 5 phương pháp nhà cung cấp? 'provideImplA()', 'provideImplB()', v.v ... ???? – Snekse

15

Không chắc chắn điều này có phù hợp với nhu cầu của bạn không, nhưng Multibindings làm việc cho tôi khi tôi cần t nhiều phần tử cùng loại (nó tạo ra một tập hợp mặc dù).

+0

Multibindings sản xuất Bộ được đặt hàng (lặp trên các phần tử giống như các phần tử đặt hàng được liên kết với Multibinder). Điều này có nghĩa là các Bộ được sản xuất bởi Ghép nối thường tốt như một Danh sách hoặc một mảng. –

1

Thêm câu trả lời này để mọi người biết cách chèn một mảng vì điều này xuất hiện đầu tiên trên tìm kiếm của google. Tôi tin rằng một trong những sẽ làm việc:

Trong cấu hình của Module: bind(InjectedObject[].class).toInstance(someArray); hoặc như một phương pháp cung cấp:

@Provides 
InjectedObject[] getInjectedObject(@Inject Provider<InjectedObject> provider) { 
    InjectedObject[] objects = new InjectedObject[5]; 
    for (int i = 0; i < objects.length; i++) { 
    objects[i] = provider.get(); 
    } 
} 
Các vấn đề liên quan