Se le classi "ResourceManager" sono considerate non valide, quali sono le alternative?


19

Sento opinioni contrastanti come:

  • "Le classi Manager dedicate non sono quasi mai lo strumento di ingegneria giusto"
  • "Le lezioni di Manager dedicati sono (attualmente) il modo migliore per sopravvivere a un grande progetto con migliaia di risorse"

Prendiamo una classica classe ResourceManager che ha le seguenti funzionalità:

  • Carica risorse (trame, audio, modelli 3D, ecc.)
  • Assicura che le risorse vengano caricate una sola volta mantenendo una cache
  • Il riferimento conta le attività per determinare se possono essere deallocate
  • Nasconde la provenienza delle risorse effettive (ad esempio, potrebbe essere un file per risorsa o tutte le risorse in un file pacchetto, oppure le risorse potrebbero anche essere caricate sulla rete)
  • Può ricaricare risorse senza riavviare il programma, il che è estremamente utile per gli artisti che lavorano al gioco.

Prendiamo anche l'argomento "singletons are bad" fuori dal tavolo fingendo che questi oggetti ResourceManager non siano singleton, e invece vengano passati attraverso l' iniezione di dipendenza .

Poi c'è l'argomento "usa una fabbrica" ​​o "chiamalo fabbrica". Il mio problema con questo è che, sì, è una factory, ma è anche una cache e un ricaricatore (per mancanza di una parola migliore). Chiamarlo factory non lo descrive correttamente, e se lo trasformo in un factory appropriato, allora dove vengono implementate la cache e il ricaricamento?

Concordo sul fatto che le classi "Manager" sono spesso un sintomo di cattiva architettura, ma in questo caso particolare come potrebbe essere ristrutturata e conservare comunque tutte le funzionalità ? È una situazione in cui una classe "Manager" è effettivamente appropriata?


3
Forse chiamarlo un magazzino anziché una fabbrica? : P
deceleratedcaviar

Risposte:


9

Penso che il problema non sia che si tratti di un cattivo design. Il problema è che il nome "Manager" non è descrittivo, come "Aggiorna" e "Processo" e "Attore". È inutile per qualcuno che tenta di comprendere questo sistema e crea confusione se si hanno mai altre classi che eseguono operazioni sugli asset.

Tuttavia, nominare le cose in un modo che trasmetta in modo efficiente il loro scopo è davvero, davvero difficile . La maggior parte dei sistemi sono troppo complicati per essere resi evidenti dal loro nome. Il meglio che puoi fare è cercare di restringere quale idea specifica rende questa classe coerente, e quali altre classi devono essere ovviamente diverse, e scegliere una parola unica che si adatta.

IMHO, la caratteristica più importante di un buon nome è che è unica nel contesto in cui la gente lo vedrà (la base di codice), ed è facile da ricordare. Il test dovrebbe essere che puoi conversare con i tuoi compagni di squadra che hanno familiarità con il codice senza dover chiarire a cosa ti riferisci. Ciò sarebbe di grande aiuto anche nel caso in cui fosse necessario scrivere documentazione di riferimento.

Infine, considera che se non riesci a descrivere quell'idea coesiva, potrebbe non essere molto coerente. Ad esempio, è possibile separare la memorizzazione nella cache e il conteggio dei riferimenti in un AssetCache e mantenere il caricamento in un AssetLoader. Ma questo dipende davvero da quanto sia complicato e intrecciato il codice.

Ma se il tuo AssetManager è abbastanza coerente e nient'altro nel tuo gioco è AssetManagery, allora potrebbe essere un nome perfettamente valido.


La separazione AssetLoader / AssetCache non è una cattiva idea.
Tom Dalling,

4

"Faccio questo in un posto o lo faccio molti?"

La logica di caricamento è di solito centralizzata su un singolo punto di accesso perché tende a essere eseguita solo nei punti chiave dell'applicazione, dove stiamo cercando di toglierlo il più presto possibile. Questo di solito avviene all'avvio dell'app, all'avvio a livello di gioco o quando la posizione mondiale del giocatore richiede il caricamento di un nuovo blocco per garantire un'esperienza senza interruzioni. Considerando che questo viene fatto come un processo batch (sia in un grosso blocco che in molti più piccoli non importa davvero), ha senso avere un metodo o un insieme di metodi da chiamare, per dare il via a questo processo.

Sulla maggior parte delle piattaforme, il caricamento è asincrono, quindi in realtà non hai altra scelta che mantenere separati i flussi di codice per il caricamento e la logica di altre app, un altro motivo per l'astrazione delle funzioni di gestione delle risorse nella propria classe.

Infine, alcuni punti su cui riflettere:

Il caricamento delle risorse non viene eseguito molto spesso rispetto ad es. logica di gioco, quindi vale la pena aggiungere complessità ai singoli oggetti di gioco per farlo? Gli oggetti di gioco sono generalmente tenuti il ​​più possibile leggeri e sono destinati solo a ciò che è necessario durante la simulazione.

Un oggetto dovrebbe essere responsabile della propria creazione e distruzione? Ciò può causare grossi mal di testa durante la gestione delle entità. Se ti aspetti che un oggetto esegua il proprio processo di creazione (incluso ottenere dipendenze delle risorse), allo stesso modo avrà la responsabilità di distruggere se stesso. Ciò può causare puntatori penzolanti / nulli, quindi deve essere gestito dall'esterno. Vedi questa risposta delineando questo problema in modo più dettagliato.


PS A parte i soliti argomenti di tipo "Singletons terribile" (che sono terribilmente dogmatici), hai mai visto un buon argomento contro i ResourceManagers? "Le classi Manager dedicate non sono quasi mai lo strumento di ingegneria giusto" non è affatto un argomento per questo caso specifico .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.