Qual è la motivazione dietro l'annotazione @ImplementedBy in Guice?

7

Di recente ho letto sull'annotazione @ImplementedBy disponibile in Google Guice . Consente al programmatore di specificare un'associazione tra un'interfaccia e la sua implementazione per l'uso futuro nell'integrazione delle dipendenze. È un esempio di associazione in tempo limitato .

Sono abbastanza abituato a definire collegamenti espliciti nei miei moduli, usando la seguente sintassi:

bind(SomeInterface.class).to(SomeInterfaceImplementation.class);

Secondo la documentazione, questo è equivalente al seguente uso dell'annotazione @ImplementedBy :

@ImplementedBy(SomeInterfaceImplementation.class)
public interface SomeInterface {
    //method declarations
}

L'unico guadagno che posso vedere qui è che il codice è leggermente più corto. Allo stesso tempo, questo approccio ha uno svantaggio giustamente sottolineato dagli stessi documenti:

Use @ImplementedBy carefully; it adds a compile-time dependency from the interface to its implementation.

Tale dipendenza potrebbe non essere un problema in molti casi, ma personalmente la vedo come un odore di codice.

Quali casi d'uso rendono utile l'annotazione @ImplementedBy ?

Un modo possibile sembra essere quello di impiegarlo nel codice di una libreria o di un framework. Come descritto nei documenti, l'annotazione può fornire un binding predefinito facilmente sostituito da uno esplicito.

If a type is in both a bind() statement (as the first argument) and has the @ImplementedBy annotation, the bind() statement is used. The annotation suggests a default implementation that can be overridden with a binding.

In questo modo, come sviluppatore di una libreria, posso fornire ai miei utenti un binding che può essere personalizzato da qualche parte nel codice client.

Questa è l'unica ragione per cui esiste l'annotazione? O c'è qualcosa che mi manca? Posso ottenere qualcosa utilizzando il codice che è solo un'applicazione che si occupa di alcune logiche di business e non una libreria / framework da estendere?

    
posta toniedzwiedz 16.05.2015 - 20:38
fonte

1 risposta

7

Penso che il pericolo qui stia usando solo l'annotazione @ImplementedBy . Usato in modo appropriato, insieme alle dichiarazioni bind() nel tuo modulo e così via, va bene.

Avere un'implementazione predefinita è ottimo per i test; non devi necessariamente definire esplicitamente un'iniezione fittizia ogni volta che stai testando una classe che ha molte dipendenze, o se hai una classe dalla quale dipendono molte cose (quindi devi definire una simulazione ogni volta ).

Ad esempio, potresti avere una classe:

@ImplementedBy(NoOpDataService.class)
interface DataService {
    Map<String, MyPOJO> getData();
}

E quindi NoOpDataService è:

class NoOpDataService implements DataService {
    @Override
    public Map<String, MyPOJO> getData() {
        return Collections.emptyMap();
    }
}

Non lo userai mai nel tuo codice attuale, ovviamente; nel tuo modulo Guice dovresti associare un'implementazione che effettivamente fa qualcosa. Ma tutti i test su classi che ottengono un% co_de iniettato non hanno più bisogno di un binding fittizio.

tl; dr Sono d'accordo con te che avere le tue interfacce dipende dalla tua implementazione può essere un odore di codice; ma può anche rimuovere il codice boilerplate per facilitare le prove. Non è una caratteristica difficile da implementare; e mentre c'è un piccolo potenziale di abuso, alla fine le conseguenze non possono essere troppo brutte (un servizio si avvia di sorpresa), e non sarebbe troppo difficile da risolvere anche se dovesse accadere.

    
risposta data 17.05.2015 - 01:20
fonte

Leggi altre domande sui tag