2015-01-28 1 views
6

Я работаю над довольно крупным проектом, у которого много инъекций. В настоящее время мы используем класс, который реализует Provider для каждой инъекции, которая нуждается в одном, и в основном они имеют одну линию get.Guice @Provides Methods vs Provider Classes

Это начинает раздражать, создавая новый класс каждый раз, когда мне нужен новый провайдер. Есть ли какая-либо польза от использования классов поставщиков по методам @Provides в моем Module или наоборот?

ответ

16

Насколько я знаю, они в точности эквивалентны для большинства простых случаев.

/** 
* 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 */ } 
} 

В любом стиле, Guice позволяет вводить Foo и Provider<Foo>, даже если ключ связан с классом или экземпляром. Guice автоматически вызывает get, если вы получаете экземпляр напрямую и создает неявный Provider<Foo>, если он не существует. Связывающие аннотации работают в обоих стилях.

Основным преимуществом @Provides является компактность, особенно по сравнению с анонимными внутренними реализациями поставщика. Однако следует отметить, что там может быть несколько случаев, когда вы хотите, чтобы благоприятствовать Provider классы:

  • Вы можете создавать свои собственные долгоживущие экземпляры провайдера, возможно, с параметрами конструктора, и привязать ключи тех случаях, а не класса литералов.

    bind(Foo.class).toProvider(new FooProvisioner("bar", "baz")); 
    
  • Если вы используете рамки, совместимые с JSR 330 (javax.inject), вы можете легко связать с классами javax.inject.Provider или экземпляров. com.google.inject.Provider расширяет этот интерфейс.

    bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class); 
    
  • Ваш Провайдер может быть достаточно сложным, чтобы фактор в свой класс. В зависимости от того, как вы структурировали свои тесты, может быть проще протестировать вашего провайдера таким образом.

  • Провайдеры могут расширять абстрактные классы. Это может быть нелегко или интуитивно, чтобы сделать это с помощью методов @Provides.

  • Вы можете связать несколько ключей с одним и тем же провайдером напрямую. Каждый метод @Provides создает ровно одну привязку, хотя вы можете связать другие ключи с ключом (здесь @Quux Foo), и пусть Guice сделает второй поиск.

  • Провайдеров легко украсить или обернуть, если вы хотите (например) кешировать или memoize экземпляры без использования областей или привязок Guice.

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

ВАЖНЫ: Хотя это хорошая стратегия для классов, которые Guice не может создавать, иметь в виде, что Guice может автоматически создавать и впрыснуть Provider<T> для любого T, что вы bind в любом случае, включая имя класса, ключ или экземпляр. Нет необходимости создавать явный провайдер, если не существует реальной логики вашего собственного участия.