Async Attesa e segregazione dell'interfaccia

0

Attualmente sto lavorando con la seguente astrazione.

 public interface IFileRepository
    {
        void Save(string identifier, byte[] content);
        Task SaveAsync(string identifier, byte[] content);
        string GetUri(string identifier);
    }

I servizi applicativi utilizzerebbero questa interfaccia per salvare i file su una posizione basata su un determinato identificatore e anche per recuperare un Uri in base a tale identificativo.

Questo costringe già alcuni clienti a sapere più del necessario. Ad esempio, un client che recupera e prepara un elenco di prodotti per mostrarlo in una pagina HTML non deve sapere come salvare un'immagine di un prodotto, ma solo come accedere a quell'immagine tramite un dato Uri .

Allo stesso modo alcune implementazioni potrebbero supportare il modello di programmazione async/await che impone i metodi a Task signature. Non solo questo è un dettaglio di implementazione, ma anche alcune implementazioni inizieranno a lanciare NotImplementedException poiché potrebbero non supportare il modello async/await . Mentre la prima violazione dell'ISP potrebbe non fare molto male, la seconda penso che raddoppierà quasi alcune interfacce solo perché un'implementazione supporta il modello di programmazione asincrona / attendi.

Come crei in modo efficiente questi tipi di astrazione in modo da essere sempre in linea con i principi SOLID?

Il mio primo pensiero è

public interface IFileRepository
{
    void Save(string identifier, byte[] content);
    string GetUri(string identifier);
}

public interface IAsyncFileRepository : IFileRepository
{
    Task SaveAsync(string identifier, byte[] content);
}

Ma temo di finire nello stesso buco.

    
posta Adrian Iftode 12.02.2017 - 16:42
fonte

2 risposte

1

Se non ti piace combinare le API in un'unica interfaccia, puoi sempre utilizzare più interfacce, o delegare firme e saltare le interfacce interamente.

Ignorando i principi SOLID (principalmente a causa del problema del culto del carico), perché l'implementatore delle interfacce dovrebbe implementare sia le versioni sincrone che asincrone di ciascuna API? O il metodo fornisce un comportamento asincrono utile, oppure no. Quindi dovresti usare solo uno o l'altro.

Vedi Devo esporre wrapper asincroni per i metodi sincroni?

    
risposta data 15.02.2017 - 23:48
fonte
0

Penso che dry e kiss siano comunque più importanti che solidi. L'interfaccia così com'è si ripete perché lo stesso metodo è essenzialmente lì due volte e così facendo rende anche l'implementazione più complessa e solleva queste domande.

Definirei solo due metodi sincroni. Quindi ci sono solo due usi molto semplici da capire. Il chiamante può raccogliere l'onere del wrapping o chiamare in modo asincrono se deve essere chiamato in quel modo.

Se un'interfaccia definisce un metodo Get and Save mi sta dicendo che il servizio chiamerà o ad un certo punto e l'implementatore deve implementare entrambi. Se questo non è il caso, non penso che dovrebbero essere nella stessa interfaccia.

    
risposta data 16.02.2017 - 19:18
fonte

Leggi altre domande sui tag