2015-01-28 11 views
6

Sto lavorando a un progetto abbastanza grande che ha molte iniezioni. Al momento utilizziamo una classe che implementa Provider per ciascuna iniezione che ne richiede uno e in genere ha una riga con i metodi get.Guice @Provides Methods vs Provider Classes

Sta diventando fastidioso creare una nuova classe ogni volta che ho bisogno di un nuovo provider. C'è qualche vantaggio nell'usare le classi di provider nei metodi @Provides nel mio Module o viceversa?

risposta

16

Per quanto ne so, sono esattamente equivalenti per i casi più semplici.

/** 
* 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 entrambi stile, Guice consente di iniettare Foo e Provider<Foo>, anche se la chiave è legato a una classe o istanza. Guice chiama automaticamente get se ottiene direttamente un'istanza e crea un numero implicito Provider<Foo> se non esiste. Le annotazioni vincolanti funzionano in entrambi gli stili.

Il vantaggio principale di @Provides è la compattezza, soprattutto rispetto alle implementazioni interne anonime del provider. Si noti, tuttavia, che ci potrebbero essere alcuni casi in cui ci si vuole favorire classi Provider:

  • È possibile creare istanze longevi Provider, possibilmente con parametri del costruttore, e si legano chiavi per quei casi invece di letterali di classe.

    bind(Foo.class).toProvider(new FooProvisioner("bar", "baz")); 
    
  • Se stai usando un quadro compatibile con JSR 330 (javax.inject), si può facilmente associare alle classi javax.inject.Provider o istanze. com.google.inject.Provider estende questa interfaccia.

    bind(Foo.class).toProvider(SomeProviderThatDoesntKnowAboutGuice.class); 
    
  • Il tuo Provider può essere abbastanza complesso da far parte della sua stessa classe. A seconda di come hai strutturato i test, potrebbe essere più semplice testare il tuo provider in questo modo.

  • I provider possono estendere classi astratte. Potrebbe non essere facile o intuitivo farlo con i metodi @Provides.

  • È possibile associare più chiavi allo stesso Provider direttamente. Ogni metodo @Provides produce esattamente un'associazione, sebbene sia possibile associare altre chiavi alla chiave (@Quux Foo qui) e consentire a Guice di eseguire una seconda ricerca.

  • I provider sono facili da decorare o avvolgere, se si desidera (ad esempio) memorizzare o memorizzare istanze senza utilizzare gli ambiti Guice o associazioni.

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

IMPORTANTE: Anche se questa è una buona strategia per le classi che Guice non può creare, tenere a mente che Guice può creare e iniettare un Provider<T> per qualsiasi T automaticamente che si bind in qualsiasi modo, incluso il nome di una classe, chiave o istanza. Non è necessario creare un fornitore esplicito a meno che non ci sia una vera e propria logica.