2012-08-15 5 views
7

Desidero creare un'istanza di un account utente. Posso usare una fabbrica come questa:Google Guice non è solo un'altra fabbrica?

public class UserFactory { 
    public User newUser(UserType type) { 
    if (type == UserType.FREE) return new FreeUser(); 
    } 
} 

User user = UserFactory.newUser(UserType.FREE); //UserType.FREE is an enum 

Ora, se io uso Google Guice, devo scrivere un "modulo":

public class UserModule extends AbstractModule { 

    public voidSetType(UserType type) { 
    this.type = type; 
    } 

    @Override 
    protected void configure() { 
    if (this.type = UserType.FREE) 
     bind(User.class).to(FreeUser.class); 
    else bind ..... 
    } 
} 

Quindi, questo è il codice cliente:

Injector injector = Guice.createInjector(new UserModule().setType(UserType.FREE))); 

La mia domanda è: Invece di scrivere una classe di fabbrica, devo scrivere una classe di modulo. E dall'esempio sopra, non vedo alcun vantaggio. La classe del modulo utilizza la riflessione, è più lenta della mia istruzione di assegnazione nella classe factory. La classe del modulo non è più semplice della classe di fabbrica. Invece di mantenere la fabbrica, devo mantenere il modulo.

Qual è il vero vantaggio comunque? Google Guice non è solo un'altra classe di fabbrica?

risposta

8

Non si vede un vantaggio poiché Guice (Dependency Injection) non è progettato per sostituire factories. Può fare a un livello limitato (vedi AssistedInject e Provider) ma se hai una logica nella tua fabbrica, è improbabile che tu possa usare Guice come sostituto diretto.

Il modo Guice per questo sarebbe avere ancora una fabbrica e Guice inietterebbe la fabbrica. Ora l'utente suona come un oggetto dominio e molto probabilmente non richiede un albero delle dipendenze iniettato da Guice. Se lo fa, la fabbrica dovrebbe essere a conoscenza di Guice e prendere Provider s per ogni tipo di Utente o avere accesso diretto a Inject per creare oggetti User usando diversi Key s.

DI è tutto sugli alberi di dipendenza. Le fabbriche si occupano di produrre oggetti senza che il chiamante debba preoccuparsi di come l'oggetto è implementato. Hanno attraversato e possono essere usati insieme, ma stanno affrontando diversi problemi.

0

Hai davvero bisogno di "UserType"?

considerare questo:

class FreeUser extends User {...} 
class NonFreeUser extends User {...} 

void configure() { 
    // if Type=Free 
    bind(User.class).annotatedWith(Free.class).to(FreeUser.class); 
    // else 
    bind(User.class).to(NonFreeUser.class) 
} 

e poi

class SomeClassThatNeedsAFreeUser { 
    @Inject 
    @Free 
    private User user; 

} 

in modo che quando si utilizza injector.getInstance (SomeClassThatNeedsAFreeUser.class), si otterrà un grado che ha automaticamente un FreeSUer iniettato ... Penso che questo sia un approccio molto migliore rispetto all'accoppiamento stretto attraverso fabbriche specifiche.

+0

Lo pseudo-codice a mano, non verrà compilato se non si risolvono le parti mancanti –

+0

Ho bisogno di UserType perché voglio che gli utenti scelgano il tipo di account che desiderano registrare. Se scelgono Free, il browser invierà il parametro "Free", è una stringa, non è sicuro, quindi lo convertirò in enum. –

2

Guice è decisamente NON solo una fabbrica. Ha lo scopo di ridurre lo schema di costruzione dei collaboratori nel sistema e di separare la responsabilità di creare le dipendenze di questi collaboratori. Le ragioni di questo sono:

  1. codice standard ridotta (se lo fate a destra)
  2. dipendenze sono astratti, e quindi può essere scambiato in presso:
    • tempo di prova - falsi/finto implementazioni/stub può essere scambiato in
    • tempo di esecuzione - implementazioni alternative possono essere scambiate quando le funzionalità cambiano.
  3. considerazioni principio di progettazione come "Interface segregazione" e "Responsabilità singolo"

Come un'altra risposta detto, c'è crossover tra dipendenza-iniezione e fabbriche - entrambi coinvolgono oggetti essere gestite e aventi la dipendenze soddisfatte da un sistema esterno, ma funzionano in modo diverso. In questo caso, vorrai la fabbrica. Ma con Dependency-Injection, se hai molte fabbriche che richiedono l'un l'altro per funzionare correttamente, puoi avere un framework di iniezione delle dipendenze come Guice gestire l'interdipendenza delle fabbriche senza un sacco di codice di cablaggio manuale e altro standard.

Tendo a piacere suddividere le dipendenze esistenti in alcuni tipi diversi e considerare l'iniezione solo per alcuni tipi.

 
+======================+=============================+====================+ 
| Type     | Note      | Inject?   | 
+======================+=============================+====================+ 
| Static Dependencies | Inherited types    | N/A    | 
+----------------------+-----------------------------+--------------------+ 
| Collaborators  | Services, Factories, etc. | Definitely   | 
+----------------------+-----------------------------+--------------------+ 
| Configuration  | Context      | Maybe - be careful | 
+----------------------+-----------------------------+--------------------+ 
| Consumables/Data  | Value types     | No - use factories | 
+======================+=============================+====================+ 

Naturalmente, senza regole sono duro e veloce, ma in generale, cerco di non iniettare i tipi di valore, a meno che non sono in uso immutabilmente come contesto per l'intero ambito degli oggetti dipendenti.

Quindi, utilizzare un tipo di utente come contesto, ad esempio, per una richiesta va bene, ma solo se è immutabile e fornito come "contesto globale" per tutti gli oggetti il ​​cui ambito è tale richiesta. Ma se intendo operare su quell'Utente, lo gestirò con le fabbriche, probabilmente in un altro flusso di lavoro/richiesta separata.

Automated iniezione di dipendenza è grande per la gestione dei collaboratori, dei servizi, classi di utilità - i grandi pezzi della vostra applicazione. Ovviamente puoi ridurlo al livello micro, ma devi essere abbastanza attento a non impazzire con questo, o ad essere consapevole dei compromessi in termini di complessità. Sì, il tuo codice diventerà più generico e più riutilizzabile e astratto, ma anche gli effetti avranno cause meno ovvie (un errore ora può essere il risultato dell'inizializzazione molto prima nel sistema in esecuzione), il tuo flusso sarà meno lineare e il tuo codice può sembrare più magico.

Se vi trovate a scrivere molto più codice del modulo che si sta salvando dal cablaggio manuale, poi ri-prendere in considerazione il vostro disegno.

Note a margine: 1. È possibile derivare framework Guice e Dependency-Injection rifasando le fabbriche e il codice di cablaggio all'estremo, ma le fabbriche sono specificatamente finalizzate a gestire classi particolari - Guice è generico per definizione, quindi non è adatto per sostituire alcuni tipi di fabbriche. Fabbriche di puro boilerplate, forse. 2. è possibile iniettare i tipi di valore che utilizzano l'iniezione, ma ti trovi in ​​difficoltà - i tipi di valore (oggetti di dominio) possono richiedere cicli di dipendenza legittimamente, che Guice e gli altri non sono realmente destinati, anche se lo supportano. Stai giocando con il fuoco, ma in un sistema in cui tutti comprendono lo stile e l'approccio, può essere potente. Usare con estrema cautela.