2013-05-01 38 views
11

Tôi muốn tiến hành một chuỗi các yếu tố xử lý và nối chúng lại với nhau thông qua Guice. Giả sử đường dẫn sau:Guice hỗ trợ tiêm sâu hơn xuống hệ thống phân cấp phụ thuộc

  • interface A thực hiện bởi class AImpl cần một số đầu vào
  • interface B thực hiện bởi class BImpl nhu cầu A
  • interface C thực hiện bởi class CImpl nhu cầu B
  • interface D thực hiện bởi class DImpl nhu cầu C

Sự phụ thuộc của A chỉ có thể được giải quyết trong thời gian chạy chứ không phải ở thời gian cấu hình. Cách tiếp cận thông thường sẽ được sử dụng tiêm được Hỗ trợ trong trường hợp này để tạo ra một nhà máy, mà sẽ đưa các trường hợp mất tích như các thông số, chỉ cần như thế này:

public interface AFactory { 
    public A createA(String input); 
} 

Nhưng những gì tôi thực sự muốn là một cái gì đó như thế này:

public interface DFactory { 
    public D createD(String inputForA); 
} 

Tôi không muốn chuyển một cách thủ công AImpl phụ thuộc cụ thể thông qua toàn bộ hệ thống phân cấp. Có thể đạt được điều này với Guice không? Nếu không, cách tốt nhất để phá vỡ vấn đề này một cách thanh lịch trong khi vẫn giữ lại lợi ích của việc tiêm là gì?

Trả lời

7

Cách gian lận: Thanh input trong biến tĩnh hoặc singleton ThreadLocal. Đặt nó trước khi đường ống của bạn bắt đầu và xóa nó sau khi nó kết thúc. Liên kết mọi thứ khác thông qua DI.

Cách ưa thích: Trong A, tham khảo @PipelineInput String inputString nhưng không liên kết nó trong bộ phun chính của bạn. Nếu không, hãy ràng buộc các phụ thuộc như bình thường, bao gồm tham chiếu đến @PipelineInput trong các lớp liên quan đến đường ống khác. Khi bạn cần một số D, hãy lấy nó từ việc triển khai DFactory, mà tôi đang gọi PipelineRunner.

public class PipelineRunner { 
    @Inject Injector injector; // rarely a good idea, but necessary here 

    public D createD(final String inputForA) { 
    Module module = new AbstractModule() { 
     @Override public void configure() { 
     bindConstant(inputForA).annotatedWith(PipelineInput.class); 
     } 
    }; 
    return injector.createChildInjector(new PipelineModule(), module) 
     .getInstance(D.class); 
    } 
} 

Đương nhiên, những nỗ lực bắt buộc đối với A, B, C, và D sẽ thất bại bên ngoài PipelineRunner vì thiếu một @PipelineInput String --you'll có được một CreationException khi bạn tạo các vòi phun với những người phụ thuộc không hài lòng, như bạn được phát hiện - nhưng những phụ thuộc dựa trên đường ống này nên dễ dàng tách thành một Mô-đun mà bạn cài đặt vào bộ tiêm con.

Nếu điều này quá khó hiểu, hãy nhớ rằng PrivateModules cũng là "implemented using parent injectors" và rằng toàn bộ điểm phụ thuộc là tạo phụ thuộc như inputForA có sẵn cho toàn bộ biểu đồ đối tượng theo cách tách rời.

+0

Tôi phải nhớ lại sự chấp thuận của tôi, beacuse này: "tiêm nỗ lực cho A, B , C, và D sẽ thất bại bên ngoài PipelineRunner vì thiếu một chuỗi @PipelineInput "Điều này không có tác dụng, bởi vì Guice xác minh Injectors tại thời gian cấu hình và thất bại ngay khi phát hiện ra ràng buộc không hài lòng, đó là lý do tại sao bạn không thể tạo ra hoàn thành Injector, sẽ được hoàn thành bởi con của nó. Mô-đun riêng khắc phục điều này bằng cách sử dụng một chất kết dính đặc biệt. – orsg

+0

Sai lầm của tôi; bạn phải ràng buộc A, B, C và D liền kề với hằng số. Không đáng kể để sửa chữa. Đã cập nhật câu trả lời. –

+1

Được rồi, vì vậy tôi phải ràng buộc tất cả mọi thứ có liên quan đến các đường ống độc quyền bên trong các vòi phun trẻ em và các vòi phun mẹ chỉ biết về nhà máy ("PipelineRunner"). – orsg

1

Tôi thấy ba tùy chọn. Chúng phụ thuộc vào tần suất bạn thay đổi input cho A.

1) Ràng buộc input làm hằng số trong mô-đun của bạn. Điều này chỉ hoạt động, nếu bạn biết giá trị đó trước khi bạn tạo Injector và không bao giờ muốn thay đổi giá trị. Xem bindConstant

2) Sử dụng mô-đun con riêng tư liên kết A hoặc giá trị cho input bên trong mô-đun đó. Về cơ bản bạn có thể có hai hoặc ba đồ thị ví dụ với giá trị khác nhau. Xem newPrivateBinder.

3) Sử dụng một Scope ala RequestScope, SessionScope ... Bằng cách này bạn có thể thay đổi các đầu vào thường xuyên nhưng bạn phải nhập/rời khỏi phạm vi tại một số điểm được xác định. Xem Custom Scopes để biết ví dụ.

+0

1) quá muộn và 2) chỉ là trường hợp đặc biệt là 1). Tôi cũng nghĩ về phạm vi, nhưng đó là quá nhiều bản mẫu cho một vấn đề nhỏ như vậy mà tôi thà bỏ DI hoàn toàn vì lợi ích của thanh lịch: -/ – orsg

Các vấn đề liên quan