Quando dovrebbe essere restituito un CallableFoo su un Foo?

1

Ho un repository che contiene le credenziali di accesso

interface LoginCredentialRepository {

    LoginCredential fetchCredentials(String username);
}

Per questo framework, sto designando un thread per gestire tutte le attività basate su IO. Questo è solo per convenzione e se qualcuno vuole davvero inviare un'attività basata su IO a un diverso Executor , suppongo che possano farlo.

Perché intendo avere questo thread IO designato, dovrei cambiare l'interfaccia in

Callable<LoginCredential> fetchCredentials(String username);

In modo che il chiamante deve solo fare

ioThread.submit(repository.fetchCredentials("foo"));

invece di qualcosa di simile

ioThread.submit(() => return repository.fetchCredentials("foo"));

Da una parte, poiché so che il modo consigliato di elaborare attività IO è di inviarle all'IO Thread, mi sento come se dovessi rendere più semplice il lavoro del chiamante e solo restituirgli quello che verrà utilizzato.

D'altra parte, il repository sa che quando viene chiamato fetchCredentials , in realtà non restituirà le credenziali, ma piuttosto un modo di recuperare le credenziali, richiedendo al chiamante di fare

Future<LoginCredential> credentialFuture = ioThread.submit(repository.fetchCredentials("foo"));
LoginCredentials credentials = credentialFuture.get();
    
posta Zymus 07.09.2016 - 04:46
fonte

2 risposte

1

I feel like I should make the caller's job easier . . .

Sì, dovresti. Come ha detto Josh Bloch in Come progettare una buona API e perché è importante ,

Don't Make the Client Do Anything the Module Could Do

È maiuscolato in questo modo perché lo considera abbastanza importante da renderlo il titolo di una sezione. Sebbene, come suggerisce Daniel Earwicker, un fraseggio più letterale del principio sarebbe

Don't make the client do anything that a large number of clients would be expected to do.

Seguendo questo principio, potrebbe essere ancora meglio restituire un Future<Foo> . Per motivi di manutenibilità, potresti voler implementare il metodo che restituisce un Future<Foo> in termini di un altro metodo che restituisce un Callable<Foo> , che a sua volta sarebbe implementato in termini di un metodo sincrono che restituisce un Foo . Potresti o meno voler esporre tutti questi metodi al di fuori del pacchetto.

    
risposta data 07.09.2016 - 06:02
fonte
1

L'asincronismo è raramente veramente necessario. Ma quando è, in base alla mia (piccola) esperienza, il design che funziona meglio è quando la responsabilità per gestire l'asincronismo è completamente presa dal framework o non è affatto presa e delegata all'utente del framework. Restituire un Callable dalla tua API è come essere nella zona grigia ed è molto poco chiaro chi è responsabile della gestione di cosa .

Quindi ci lascia con tre casi

L'asincronismo non è realmente necessario

Semplice, l'API sembra LoginCredential fetchCredentials(String username);

L'asincronismo è necessario ma non vuoi gestire tutte quelle cose

L'API rimane la stessa, l'utente del framework lo gestisce come vuole (con un buon vecchio Thread , Executor , ...)

L'asincronismo è necessario e lo gestisci

In questo caso, restituirei Future perché le cose sono chiare:

  1. Il risultato non è direttamente disponibile
  2. Il framework gestisce tutte le cose asincrone

Future<LoginCredential> fetchCredentials(String username);

    
risposta data 07.09.2016 - 10:46
fonte

Leggi altre domande sui tag