Quali alternative a un singleton ci sono per una classe che può avere solo un'istanza?

5

Ho bisogno di rappresentare un'astrazione su varie parti dell'hardware per un gioco. Sto cercando di disaccoppiare il codice che fa cose come gestire la logica del gioco dal codice che è specifico per API / piattaforma o brutto dettaglio di implementazione.

In questo modo:

std::unique_ptr<IDevice> device(CreateDevice());

IGraphicsDevice *graphics = device->getGraphicsDevice();
ISoundDevice *sound = device->getSoundDevice();
IWindow *window = device->getWindow();
IJobManager *jobmanager = device->getJobManager();
//etc

Una soluzione che ho visto era semplicemente mettere tutto questo come globale e inizializzarle in main , ma vorrei evitarlo se posso perché non mi piace davvero trattare con i globali (e io trovarli "brutti", per la mancanza di una parola migliore). Inoltre, non posso consentire più di un'istanza perché richiede l'inizializzazione delle librerie che sono inizializzate a livello globale.

Quali alternative al modello singleton ci sono per questo?

So che più di un'istanza potrebbe portare a errori, si tratta di una cattiva decisione di progettazione? Posso fare qualcosa di diverso?

    
posta user112513312 18.11.2015 - 12:12
fonte

2 risposte

12

Questo è chiamato Singleton Pattern ed è considerato un anti-pattern da molte persone al giorno d'oggi, dal momento che nasconde le dipendenze e rende il tuo codice meno mantenibile.

La necessità di utilizzare il modello singleton può derivare da altre decisioni sbagliate, ma non posso giudicare poiché non conosco la tua architettura e il tuo design.

Ad ogni modo, lasciatemi fare un esempio su come sbarazzarmi di questo schema. In un gioco ci sarà probabilmente una sorta di ciclo principale che chiama tutto il resto. Per semplicità, supponiamo che questo ciclo principale sia contenuto in un oggetto, ma questo non è obbligatorio. Quando crei l'oggetto che contiene il ciclo, passi gli oggetti che hai creato nel tuo codice di esempio (o piuttosto riferimenti ad essi) a quell'oggetto. È possibile passarli tramite un costruttore appropriato o tramite metodi setter per menzionare gli esempi più comuni. Come fai questo nel tuo ciclo principale dipende strongmente dalla tua progettazione di classe, ma potresti eseguire il rendering in modo simile a questo

while(running)
{
    game_state->update();
    renderer->render_state(game_state);
}

Gli adepti di questo approccio sono la necessità di eliminare oggetti globali o singleton e di evitare che i tuoi oggetti sappiano come creare gli oggetti del tuo dispositivo. L'unica cosa che i tuoi oggetti devono sapere è che ci sono alcune astrazioni del dispositivo che possono usare. Non devono sapere altro.

Questo approccio si chiama Dependency Injection ed è considerato un modello molto importante della moderna progettazione OO.

    
risposta data 18.11.2015 - 12:37
fonte
-3

Risolvi questo passaggio passando l'istanza IDevice alle istanze che ne hanno bisogno, e istanzia solo la classe nella funzione principale. Questo rende anche le dipendenze più esplicite.

    
risposta data 18.11.2015 - 12:35
fonte

Leggi altre domande sui tag