2015-01-28 7 views
6

Ich arbeite an einem ziemlich großen Projekt, das eine Menge Injektionen hat. Wir verwenden derzeit eine Klasse, die Provider für jede Injektion implementiert, die eine benötigt, und sie haben meistens eine Zeile get Methoden.Guice @Provides Methoden vs Provider Klassen

Es wird langsam nervig, jedes Mal, wenn ich einen neuen Anbieter brauche, eine neue Klasse zu erstellen. Gibt es einen Vorteil für die Verwendung von Provider-Klassen über @Provides Methoden in meinem Module oder umgekehrt?

Antwort

16

Soweit ich weiß, sind sie in den meisten Fällen genau gleichwertig.

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

In jedem Stil, Guice können Sie injizieren Foo und Provider<Foo>, auch wenn der Schlüssel zu einer Klasse oder Instanz gebunden ist. Guice ruft automatisch get auf, wenn eine Instanz direkt abgerufen wird, und erstellt eine implizite Provider<Foo>, falls eine nicht existiert. Bindungsanmerkungen funktionieren in beiden Stilen.

Der Hauptvorteil von @Provides ist die Kompaktheit, insbesondere im Vergleich zu anonymen internen Provider-Implementierungen. Beachten Sie jedoch, dass es möglicherweise ein paar Fälle, in denen man sich wünschen Provider Klassen bevorzugen:

  • Sie können Ihre eigenen langlebigen Provider-Instanzen, möglicherweise mit Konstruktorparameter und binden Schlüssel zu diesen Instanzen erstellen anstelle von Klassenliteralen.

    bind(Foo.class).toProvider(new FooProvisioner("bar", "baz")); 
    
  • Wenn Sie einen Rahmen kompatibel mit JSR 330 (javax.inject) verwenden, können Sie leicht zu javax.inject.Provider Klassen oder Instanzen binden. com.google.inject.Provider erweitert diese Schnittstelle.

    bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class); 
    
  • Ihr Provider kann komplex genug sein, um in seine eigene Klasse einzuordnen. Je nachdem, wie Sie Ihre Tests strukturiert haben, ist es möglicherweise einfacher, Ihren Provider auf diese Weise zu testen.

  • Anbieter können abstrakte Klassen erweitern. Es ist möglicherweise nicht einfach oder intuitiv, dies mit @Provides-Methoden zu tun.

  • Sie können mehrere Schlüssel direkt an denselben Provider binden. Jede @Provides-Methode erzeugt genau eine Bindung, obwohl Sie andere Schlüssel an den Schlüssel (@Quux Foo hier) binden könnten und Guice eine zweite Suche durchführen lassen.

  • Provider sind einfach zu dekorieren oder zu umbrechen, wenn Sie beispielsweise Instanzen in Cache speichern oder memoisieren möchten, ohne GUICE-Bereiche oder -Bindungen zu verwenden.

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

WICHTIG: Obwohl dies eine gute Strategie für Klassen, die Guice nicht bedenken erstellen, die Guice automatisch erstellen und eine Provider<T> für jede T injizieren, die Sie bind in irgendeiner Weise, einschließlich eines Klassennamens, Schlüssels oder einer Instanz. Es ist nicht nötig, einen expliziten Provider zu erstellen, es sei denn, es ist die eigene Logik involviert.