Pipeline di dati con fallback e callback

2

Sto refactoring il nostro attuale design per come scarichiamo i dati statici. È un casino di gerarchia di classi profonde e inferno di callback e voglio convertirlo in un design lineare più elegante.

Ecco due esempi dei passaggi che eseguiamo per scaricare i dati statici (file JSON):

Esempio 1, scaricando il manifest principale:

  • Tentativo di caricare il file manifest dal disco locale
    • In caso di errore, scarica da Internet
    • Se non riesci a scaricare, salva con errore
    • In caso di successo, restituisci dati stringa
    • In caso di successo, deserializza il file manifest
    • Per ogni file nel manifest, tenta di caricare dal disco locale
      • In caso di successo, deserializza e restituisci
      • In caso di errore, scarica da Internet
      • Se il download ha esito positivo, restituisci i dati stringa
      • Deserializza e ritorna
      • Se il download non riesce, salva l'errore
    • Quando tutti i file sono deserializzati, restituisci tutti i risultati in un elenco

Esempio due, scarica un file specifico:

  • Chiedi al gestore manifest di ottenere una versione specifica del file
    • Se il gestore manifest lo ha memorizzato, torna
    • Se il gestore manifest non lo ha archiviato localmente, prova a scaricarlo
    • Se il download ha esito positivo, deserializza e restituisce
    • Se il download non riesce, salva l'errore

Attualmente, ogni passo è un metodo in ... qualche classe nella gerarchia, e le sottoclassi sovrascrivono alcuni passaggi per adattarsi ad un involucro speciale (ad esempio non utilizzare manifest manager, non tentare di scaricare, ecc.). / p>

Quasi ogni passaggio utilizza i callback a causa della natura del download di materiale da Internet. E così, abbiamo finito per dover ignorare i callback in ... alcune classi nella gerarchia, che hanno portato a un pasticcio completo e illeggibile.

Il mio primo tentativo di refactoring è stato quello di utilizzare il pattern di progettazione Decorator o Chain of Responsibility. Il fatto è che alcuni passaggi richiedono il CdR e altri no. Inoltre, alcuni passaggi (se non tutti) utilizzano i callback, che non sembrano i pattern in cui il design deve essere utilizzato. Un altro problema era che alcuni passaggi della catena trasformavano un tipo di dati (stringa) in un altro (oggetto deserializzato). E infine, non ho idea di come tradurrei "prendi il manifest scaricato e produci ogni file separatamente, e quando tutto finisce, continua la catena".

Questo è il più vicino che ho ottenuto con un mix di classi Decorator e CoR, ma non include l'ultima parte in cui abbiamo diviso e scaricato ogni file singolarmente.

var callbackReader = new CallbackGameDataReader<ManifestVO<ManifestFileVO>>();
var manifestDeserializer = new DeserializeGameDataReader<ManifestVO<ManifestFileVO>>(callbackReader);
var wwwReader = new WwwGameDataReader(remoteEnvironmentPath, manifestDeserializer);
var streamingReader = new StreamingAssetsGameDataReader(streamingAssetsManifestPath, manifestDeserializer, wwwReader);
streamingReader.Read(dataId, o =>
{
    ManifestVO<ManifestFileVO> localManifest = (ManifestVO<ManifestFileVO>)o;
    localParsedData = localManifest.files;
    localKeyedData = CreateKeyedData(localParsedData);
    parsedData = localManifest.files;
    keyedData = CreateKeyedData();
    ContinueInit();
});

Inoltre non sembra molto intuitivo.

Il mio obiettivo è finire con qualcosa di simile a questo (kinda):

List<ManifestFile> dataFiles = new DataReader()
    .ReadLocal() // How do we fallback to WWW?
    .Deserialize<Manifest>()
    .Split(manifest => manifest.files)
        .ReadLocal()
        .Deserialize<ManifestFile>()
        .Merge() // ???
    .ToList();

Ho letto di Chain of Responsibility, Decorator, Future / Promises, Pipeline e ho cercato di abbracciarli. Parte del problema è che ho fatto solo manipolazioni di raccolte di base con Linq (dove, select, etc) quindi qualcosa di simile a map / reduce è ancora nuovo per me, e l'altra parte è che non sono abbastanza sicuro di come si adattano i callback con tutto ciò (eccetto forse Future / Promises).

E poi c'è la parte di fallback. Potrei avere un singolo GetFile che tenta di fare tutto localmente, ma poi, nei casi in cui il processo dovrebbe sempre utilizzare i dati locali, devo duplicare la logica.

Quindi questo è dove sono ora. Ho letto un sacco di schemi e ho cercato di capire come scegliere quello che meglio si adatta alle mie esigenze e incollarle insieme.

I miei obiettivi sono:

  • Ha bisogno di usare le callback
  • Idealmente, posso configurare i fallback (se appropriato)
  • Dovrebbe essere sicuro per il tipo (probabilmente usi i generici)
  • Tutti i passaggi devono essere (relativamente) intercambiabili (ad esempio wwwReader con localReader)

Mi piacerebbe sentire i tuoi pensieri. Qualsiasi materiale consigliato da leggere sarebbe fantastico.

Grazie!

P.S. Oltre a risolvere effettivamente il problema, la mia intenzione è di imparare come implementarlo da zero, quindi preferirei evitare l'uso di librerie esistenti

P.P.S. La soluzione deve essere eseguita in Unity, che utilizza un runtime mono personalizzato, quindi async / await non è un'opzione. E l'utilizzo di librerie potrebbe introdurre problemi durante la compilazione per dispositivi mobili.

    
posta pek 10.03.2016 - 04:26
fonte

0 risposte

Leggi altre domande sui tag