2015-01-28 20 views
6

Tôi đang làm việc trên một dự án khá lớn có rất nhiều mũi tiêm. Chúng tôi hiện đang sử dụng một lớp thực hiện Provider cho mỗi lần tiêm cần một và hầu hết chúng có một phương thức get.Guice @Provides Methods vs Provider Classes

Bắt đầu gây khó chịu khi tạo lớp học mới mỗi lần tôi cần một nhà cung cấp mới. Có lợi ích gì khi sử dụng các lớp của nhà cung cấp qua các phương thức @Provides trong Module hoặc ngược lại của tôi không?

Trả lời

16

Theo như tôi biết, chúng hoàn toàn tương đương với hầu hết các trường hợp đơn giản.

/** 
* Class-style provider. 
* In module: bind(Foo.class).annotatedWith(Quux.class).toProvider(MyProvider.class); 
*/ 
class MyProvider implements Provider<Foo> { 
    @Inject Dep dep; // All sorts of injection work, including constructor injection. 

    @Override public Foo get() { 
    return dep.provisionFoo("bar", "baz"); 
    } 
} 

/** 
* Method-style provider. configure() can be empty, but doesn't have to be. 
*/ 
class MyModule extends AbstractModule { 
    /** Name doesn't matter. Dep is injected automatically. */ 
    @Provides @Quux public Foo createFoo(Dep dep) { 
    return dep.provisionFoo("bar", "baz"); 
    } 

    @Override public void configure() { /* nothing needed in here */ } 
} 

Trong cả hai phong cách, Guice cho phép bạn bơm FooProvider<Foo>, ngay cả khi phím được ràng buộc vào một lớp học hoặc ví dụ. Guice sẽ tự động gọi số get nếu nhận được một cá thể trực tiếp và tạo ra một ngụ ý Provider<Foo> nếu không tồn tại. Chú thích ràng buộc hoạt động trong cả hai kiểu.

Ưu điểm chính của @Provides là nhỏ gọn, đặc biệt là so với việc triển khai Nhà cung cấp bên trong ẩn danh. Lưu ý, tuy nhiên, có thể có một vài trường hợp bạn muốn ủng hộ lớp Provider:

  • Bạn có thể tạo tồn tại lâu dài các trường hợp nhà cung cấp của riêng bạn, có thể với thông số nhà xây dựng, và ràng buộc các phím cho những trường hợp thay cho các lớp học.

    bind(Foo.class).toProvider(new FooProvisioner("bar", "baz")); 
    
  • Nếu bạn đang sử dụng một khuôn khổ phù hợp với JSR 330 (javax.inject), bạn có thể dễ dàng liên kết với các lớp học javax.inject.Provider hoặc trường hợp. com.google.inject.Provider mở rộng giao diện đó.

    bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class); 
    
  • Nhà cung cấp của bạn có thể đủ phức tạp để tạo thành lớp riêng. Tùy thuộc vào cách bạn đã cấu trúc các bài kiểm tra của mình, có thể dễ dàng hơn khi kiểm tra Nhà cung cấp của bạn theo cách này.

  • Nhà cung cấp có thể mở rộng các lớp trừu tượng. Nó có thể không dễ dàng hoặc trực quan để làm điều này với các phương pháp @Provides.

  • Bạn có thể liên kết trực tiếp một số khóa với cùng một Nhà cung cấp. Mỗi phương thức @Provides tạo chính xác một liên kết, mặc dù bạn có thể liên kết các khóa khác với khóa (@Quux Foo tại đây) và để Guice thực hiện tra cứu lần hai.

  • Nhà cung cấp dễ dàng trang trí hoặc bọc, nếu bạn muốn (ví dụ) bộ nhớ cache hoặc ghi nhớ các trường hợp mà không sử dụng phạm vi Guice hoặc các ràng buộc.

    bind(Foo.class).toProvider(new Cache(new FooProvisioner("bar", "baz"))); 
    

QUAN TRỌNG: Mặc dù đây là một chiến lược tốt cho các lớp học mà Guice không thể tạo, hãy nhớ rằng Guice có thể tự động tạo và tiêm một Provider<T> cho bất kỳ T mà bạn bind theo bất kỳ cách nào, bao gồm cả tên, khóa hoặc cá thể của lớp. Không cần phải tạo ra một nhà cung cấp rõ ràng trừ khi có logic thực sự của bạn tham gia.