I giochi al dettaglio usano "inversione di controllo" e "iniezione di dipendenza"?


30

Molti degli sviluppatori di software più diligenti che conosco si stanno muovendo verso l' inversione del controllo e l' iniezione di dipendenza per gestire i riferimenti agli oggetti. Dal punto di vista dei giochi Flash non conosco tutti i dettagli degli studi AAA, quindi: sono usati nel mondo dei giochi al dettaglio?


Penso che in quel mondo le prestazioni contino soprattutto, dal momento che più utenti saranno colpiti da prestazioni basse rispetto ai programmatori da codici errati.
Bart van Heukelom,

L'iniezione di dipendenza suona come un sistema basato su componenti, ma vorresti avere un esempio di come si potrebbe annullare l'inversione del controllo?
ADB il

Poiché la maggior parte di questa discussione sembra essere male informata su cosa sia l'IoC e ciò che risolve e l'OP non sta davvero chiedendo che in primo luogo indicherò qui per i futuri visitatori: sebaslab.com/ioc-container-unity-part-1
Boris Callens,

Si lo fanno. In effetti, Rare ha parlato di come stanno implementando i loro test in Sea of ​​Thieves - youtube.com/watch?v=KmaGxprTUfI&t=1s . Sfortunatamente non avevano molto da dire su Inversion of Control in Unreal Engine, tuttavia, ho scritto un progetto che dimostra come funziona: github.com/jimmyt1988/UE-Testing
Jimmyt1988

Risposte:


45

Lo chiami "diligente sviluppo di software", io lo chiamo "doloroso overengineering". Ciò non vuol dire che l'inversione del controllo sia negativa - in effetti, la definizione di base è buona - ma la proliferazione di interi quadri e metodi di lavoro per raggiungere tutto ciò è a dir poco folle, specialmente combinata con il modo in cui le persone distruggono interfacce perfettamente buone e pulite per poter iniettare componenti intercambiabili che il 99% delle volte non scambierete mai. È il genere di cose che potrebbe provenire solo dall'ambiente aziendale Java e sono contento che non abbia un punto d'appoggio altrove.

Spesso l'argomento è che anche se non si scambiano componenti, si desidera poterli testare in isolamento con oggetti similari e simili. Tuttavia, temo che non comprerò mai l'argomento secondo cui vale la pena gonfiare e complicare un'interfaccia per poterlo testare meglio. I test dimostrano solo una cosa: che i test funzionano. Le interfacce pulite e minimali d'altro canto fanno molto per dimostrare che il tuo codice funziona.

Quindi, la risposta breve: sì, ma non nel modo in cui stai pensando. A volte, quando hai bisogno di un comportamento intercambiabile, passerai un oggetto a un costruttore che detta parte del comportamento del nuovo oggetto. Questo è tutto.


5
+1 - Concordo sul fatto che la comunità Java sembra avere una situazione estremamente complicata, che sembra essere un'idea molto semplice.
Chris Howe,

4
L'idea non è necessariamente che dovrai scambiare diverse implementazioni nella produzione, ma che potresti voler iniettare implementazioni speciali per facilitare i test automatizzati. A tale proposito, DI / IoC può sicuramente essere utile nei giochi, ma si desidera mantenerlo ragionevolmente mirato. Non dovresti aver bisogno di più di alcune risoluzioni di servizio una tantum ad alto livello: non vuoi risolvere i servizi per ogni piccolo oggetto nel gioco, e certamente non tutti i frame o qualcosa del genere.
Mike Strobel,

2
@Thomas Dufour: il concetto di test non può mai provare nulla. È solo un punto dati. È possibile eseguire un test di test 100000 volte senza provare che passerà per l'esecuzione 100001. La prova proviene dall'analisi logica dell'argomento. Direi che questi contenitori IoC e simili semplificano i test a spese di rendere più dura la dimostrazione della correttezza e credo che sia una cosa negativa.
Kylotan,

13
@Kylotan il concetto di test non prova mai a provare nulla. Cerca di dimostrare che il comportamento con determinati input è come previsto. Maggiore è il comportamento dimostrato, maggiore è la tua convinzione che la funzione generale sia corretta ma non è mai al 100%. L'affermazione secondo cui un'interfaccia minimale dimostra qualcosa è ridicola.
dash-tom-bang,

5
@Alex Schearer: temo di non poter mai accettare il fatto che la necessità di utilizzare un sistema contenitore IoC formalizzato e in genere la creazione di argomenti di costruttori aggiuntivi o classi di fabbrica per facilitare i test sta, in qualche modo, rendendo il codice più ponderato, e certamente no rendendolo più libero accoppiato. In effetti calpesta praticamente l'incapsulamento, un aspetto chiave di OOP. Invece di affidarsi a TDD per guidare il loro design e sperare che emerga un buon risultato, le persone potrebbero semplicemente seguire i principi SOLID in primo luogo.
Kylotan,

17

Pattern di strategia , composizione , iniezione di dipendenza , sono tutti strettamente correlati.

Poiché il modello di strategia è una forma di iniezione di dipendenza, se dai un'occhiata a motori come Unity, ad esempio, sono completamente basati su questo principio. Il loro uso di componenti (modello di strategia) è profondamente incorporato in tutto il loro motore.

Uno dei principali vantaggi oltre al riutilizzo dei componenti è quello di evitare le temute gerarchie di classi profonde.

Ecco un articolo di Mick West che parla di come ha introdotto questo tipo di sistema nella serie di giochi Tony Hawk di Neversoft.

Fai evolvere la tua gerarchia

Fino a anni piuttosto recenti, i programmatori di giochi hanno costantemente utilizzato una gerarchia di classe profonda per rappresentare le entità di gioco. La marea sta iniziando a spostarsi da questo uso di gerarchie profonde a una varietà di metodi che compongono un oggetto entità di gioco come aggregazione di componenti ...


2
+1, evolve la tua gerarchia è un ottimo collegamento di cui mi ero completamente dimenticato. Anche le diapositive Scott Bilas sono buone: il link corretto per queste è ( scottbilas.com/files/2002/gdc_san_jose/game_objects_slides.pdf ). C'è un altro set di diapositive correlate, ma ho dimenticato dove ...
magro

Anche l'articolo in Games Gems 5 (penso) di Bjarne Rene.
Chris Howe,

13

Sembra esserci molta confusione sul modello di Inversion of Control (IoC). Un certo numero di persone lo ha identificato con il modello di strategia o un modello di componente, ma questi confronti non catturano realmente ciò che è IoC. IoC riguarda davvero come si ottiene una dipendenza. Lasciate che vi faccia un esempio:

class Game {
    void Load() {
        this.Sprite.Load(); // loads resource for drawing later
    }
}

class Sprite {
    void Load() {
        FileReader reader = new FileReader("path/to/resource.gif");
        // load image from file
    }
}

In quanto sopra è chiaro che Sprite.Loadha una dipendenza da a FileReader. Quando si desidera testare il metodo è necessario quanto segue:

  1. Un file system in atto
  2. Un file di prova da caricare dal file system
  3. Capacità di innescare errori comuni del file system

I primi due sono ovvi, ma se vuoi assicurarti che la tua gestione degli errori funzioni come previsto, hai davvero bisogno anche del n. 3. In entrambi i casi hai potenzialmente rallentato un po 'i tuoi test in quanto ora devono andare su disco e probabilmente hai reso il tuo ambiente di test più complicato.

L'obiettivo di IoC è di disaccoppiare l'uso del comportamento dalla sua costruzione. Nota come questo differisce dal modello di strategia. Con il modello di strategia l'obiettivo è incapsulare un pezzo riutilizzabile di comportamento in modo da poterlo estendere facilmente in futuro; non ha nulla da dire su come sono costruite le strategie.

Se dovessimo riscrivere il Sprite.Loadmetodo sopra, probabilmente finiremmo con:

class Sprite {
    void Load(IReader reader) {
        // load image through reader
    }
}

Ora, abbiamo disaccoppiato la costruzione del lettore dal suo uso. Pertanto, è possibile scambiare un lettore di test durante i test. Ciò significa che l'ambiente di test non ha più bisogno di un file system, file di test e può simulare facilmente eventi di errore.

Nota che ho fatto due cose nella mia riscrittura. Ho creato un'interfaccia IReaderche ha incapsulato alcuni comportamenti, ovvero implementato il modello di strategia. Inoltre, ho spostato la responsabilità della creazione del lettore giusto in un'altra classe.

Forse non abbiamo bisogno di un nuovo nome di modello per descrivere quanto sopra. Mi colpisce come un mix di modelli di strategia e fabbrica (per contenitori IoC). Detto questo, non sono sicuro dei motivi per cui le persone si oppongono a questo modello in quanto è chiaro che risolve un problema reale e, certamente, non è ovvio per me cosa abbia a che fare con Java.


2
Alex: nessuno si oppone al passaggio di oggetti già creati per guidare la funzionalità personalizzata dove necessario. Lo fanno tutti, proprio come nel tuo esempio. Il problema è dove le persone usano interi framework che esistono puramente per gestire queste cose e codificare religiosamente ogni aspetto della funzionalità per dipendere da questa funzionalità. Prima aggiungono IReader come parametro alla costruzione di Sprite, quindi finiscono per aver bisogno di speciali oggetti SpriteWithFileReaderFactory per facilitare questo, ecc. Questo atteggiamento proviene da Java e cose come i contenitori Spring IoC, ecc.
Kylotan

2
Ma non stiamo parlando di contenitori IoC - almeno non lo vedo nel post originale. Stiamo solo parlando del modello stesso. Il tuo argomento, come meglio posso dire, è "Poiché alcuni strumenti in natura sono cattivi, non dovremmo usare i concetti sottostanti". Questo mi colpisce come buttare il bambino fuori con l'acqua del bagno. Raggiungere il giusto equilibrio tra semplicità, fare le cose e manutenibilità / testabilità è un problema difficile probabilmente meglio trattato su un progetto per progetto.
Alex Schearer,

Sospetto che molte persone siano contrarie all'IoC perché significa:
phtrivier,

4

Direi che è uno strumento tra i tanti e che viene usato occasionalmente. Come diceva tenpn, qualsiasi metodo che introduce vtables (e in genere qualsiasi ulteriore indiretta) può avere una penalità di prestazione, ma questo è qualcosa di cui dovremmo preoccuparci solo per il codice di basso livello. Per un codice strutturale di alto livello che non è realmente un problema e l'IoC può avere vantaggi positivi. Tutto ciò per ridurre le dipendenze tra le classi e rendere il codice più flessibile.


2
Per essere precisi, mi preoccuperei delle penalità di vtable per qualsiasi codice che viene chiamato molte volte un frame. Questo può essere o meno di basso livello.
tenpn

4

Devo essere d'accordo con Kylotan su questo. "Dependency injection" è una brutta soluzione Java a un brutto difetto concettuale Java, e l'unica ragione per cui qualcuno la sta guardando in altre lingue è perché Java sta diventando la prima lingua per molte persone, quando in realtà non dovrebbe.

L'inversione del controllo, d'altra parte, è un'idea utile che esiste da molto tempo ed è molto utile se fatta bene. (Non nel modo Java / Dependency Injection.) In effetti, probabilmente lo fai sempre se lavori in un linguaggio di programmazione sano. Quando ho letto per la prima volta l'intera faccenda del "CIO" di cui tutti parlavano, ero completamente deluso. L'inversione del controllo non è altro che il passaggio di un puntatore a funzione (o puntatore a metodo) a una routine o a un oggetto al fine di aiutare a personalizzarne il comportamento.

Questa è un'idea che esiste dagli anni '50. E 'nella libreria standard C (qsort viene in mente) ed è tutto il luogo in Delphi e .NET (gestori di eventi / delegati). Consente al vecchio codice di chiamare un nuovo codice senza dover ricompilare il vecchio codice e viene utilizzato continuamente nei motori di gioco.


2
Ero anche del "quindi questo è ciò di cui le persone sono entusiaste?" quando leggo di DI, ma il fatto è che la maggior parte dei programmatori di giochi potrebbe sopportare di conoscerlo e di come si applicherebbe al lavoro che facciamo.
dash-tom-bang,

2

Non nella mia esperienza. È un peccato, dato che il codice dei giochi deve essere molto adattabile e questi approcci sarebbero sicuramente di aiuto.

Tuttavia, va detto che entrambi i metodi potrebbero, in C ++, introdurre tabelle virtuali dove prima non esistevano, portando con sé un successo prestazionale adeguato.


1

Non sono uno sviluppatore di giochi professionale e ho provato a implementare l'IoC in C ++ solo una volta, quindi è solo una speculazione.

Tuttavia, sospetto che gli sviluppatori di giochi sarebbero sospettosi di IoC perché significa:

1 / progettazione di molte interfacce e molte piccole classi

2 / avendo praticamente tutte le chiamate di funzione associate di recente

Ora, potrebbe essere una coincidenza, ma entrambi tendono ad essere un po 'più complicati e / o problematici per le prestazioni in C ++ (che è ampiamente usato nel gioco, non è vero?) Rispetto a Java, dove l'IoC si è diffuso (probabilmente perché era relativamente facile da fare, aiutare le persone a progettare gerarchie di oggetti più sani e poiché alcuni credevano che potesse trasformare la scrittura di un'applicazione in Java in scrittura di un'applicazione in XML, ma questo è un altro dibattito: P)

Sono interessato ai commenti se ciò non ha alcun senso;)

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.