Qual è la differenza tra XNA Game Services e le variabili globali glorificate?


10

La Microsoft.Xna.Framework.Gameclasse ha una proprietà Services che consente al programmatore di aggiungere un servizio al proprio gioco fornendo il tipo di classe e un'istanza della classe al metodo Add.

Ora, invece di dover passare un AudioComponenta tutte le classi e i metodi che lo richiedono, basta passare l' Gameistanza e cercare il servizio. ( Service Locator )

Ora, poiché i giochi hanno molti servizi (GraphicsDevice, SceneGraph, AudioComponent, EffectsManager, eccetera), ora passerai sostanzialmente a Game.

Quindi perché non trasformare queste istanze in Singleton? Bene, perché i Singleton sono cattivi perché hanno uno stato globale, impediscono i test e rendono il tuo design molto più fragile. I localizzatori di servizi sono ugualmente considerati un anti-modello per molti perché invece di passare semplicemente la dipendenza a un oggetto, si passa un localizzatore di servizi (il Gioco) che accoppia quella classe con il resto dei servizi.

Allora perché i servizi sono consigliati in XNA e nello sviluppo di giochi? È perché i giochi sono diversi dai normali programmi e sono strettamente intrecciati con i loro componenti e dover passare ogni componente necessario per il funzionamento di una classe sarebbe estremamente ingombrante? I servizi di gioco in quel momento sono un male necessario nella progettazione del gioco? Esistono alternative che non comportano lunghi elenchi di parametri e accoppiamenti?


3
"I localizzatori di servizi sono ugualmente considerati un anti-modello per molti" - [citazione necessaria]. Ovviamente usarli dove non ne hai bisogno è un male - vero per tutti i costrutti software - ma non ho mai sentito i localizzatori di servizi chiamati anti-pattern. (D'altra parte, cerco anche di evitare ai programmatori che passano la maggior parte del loro tempo a discutere delle ultime minuzie di pattern.)

@JoeWreschnig, anche se sono d'accordo con te, ho fatto qualche ricerca e ho trovato questo: blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx
Roy T.

2
Sì, ma quel ragazzo sta vendendo un libro sull'uso di DI; ovviamente non vuole che tu usi qualcosa di semplice, quindi non comprerai il suo libro! (In tutta serietà, l'articolo originale DI / SL di Fowler trattava esattamente questo argomento - martinfowler.com/articles/… - e il blog di quel ragazzo non aggiunge nulla alla discussione.)

Vorrei poter contrassegnare quel link che hai appena pubblicato da Martin Fowler come risposta (anche se non è la mia domanda)
Roy T.

Risposte:


6

Non credo che tutti siano d'accordo sul fatto che i localizzatori di servizi siano cattivi. I Service Locator forniscono un modo per disaccoppiare importanti funzionalità di cui tutti hanno bisogno dalla loro effettiva implementazione. I localizzatori di servizi forniscono anche un modo per scambiare i servizi in fase di esecuzione. Inoltre, non credo sia vero che è necessario passare ovunque intorno al localizzatore di servizi. Penso che tu possa accedervi da qualsiasi luogo. Mentre una classe di gioco con globi dovrebbe essere passata circa mille volte per fotogramma (il che causerebbe cattive prestazioni).

Per rendere un po 'più chiara la differenza tra il localizzatore di servizi e una classe con globi, considerare il seguente esempio:

Sto realizzando un gioco e utilizzo un oggetto di classe gameA con una variabile globale: il caricatore di contenuti. Ora nel mio prossimo gioco non voglio usare la classe gameA ma creare una nuova classe gameB. Ora devo aggiungere nuovamente i globuli di gioco A a gameB, che è un lavoro extra. Inoltre diventa difficile configurare il tipo di caricatore di contenuti che desidero. Supponiamo che io abbia un gioco che funziona sia sul PC che sull'XBOX. Sul PC voglio un caricatore di contenuti in grado di aprire anche una finestra di dialogo "Apri file". Mentre su XBOX sicuramente non lo voglio. Avendo un file di configurazione posso anche a metà del gioco cambiare facilmente il caricatore di contenuti, anche da qualche altra parte rispetto alla classe A del gioco, senza solo rendere i globali in gioco A tutti pubblici.

Ora considera che sto usando un localizzatore di servizi. Posso sempre continuare ad usarlo. E anche che tipo di servizi ci possono essere sempre diversi. È anche vero che non mi occuperò nemmeno della loro implementazione finché avranno un'interfaccia comune. (Anche se potrei usarlo anche in una classe come GamA).

Comunque penso che troverai i servizi di gioco abbastanza utili. Tutti quelli che conosco lo usano. Per aiutarti un po 'di più. Ho creato una piccola classe di supporto per i servizi di gioco in modo che tu possa fare un po 'meno casting tutto il tempo: http://roy-t.nl/index.php/2010/08/25/xna-accessing-contentmanager -e -dispositivo-grafica-ovunque-in qualsiasi momento-il-gameervicecontainer / Lo uso parecchio.


Grazie per la risposta. In una classe che richiederebbe un servizio, in genere richiedi semplicemente la classe GameServices per il servizio quando necessario o crei una variabile membro nella classe e richiedi il servizio solo nel costruttore? Suppongo che ciò che sto chiedendo sia quanto return (T)Instance.GetService(typeof(T));è lento .
John Pollick,

Inoltre, cosa ne pensi di questa implementazione della classe GameServices? Ho rimosso il singleton non necessario perché non aveva caratteristiche che l'astrazione non aveva già. Inoltre, ho rimosso il Servicesuffisso ridondante alla fine di ogni metodo.
John Pollick,

Inoltre, penso che il motivo per cui il AddServicemetodo Services accetta un tipo sia che tu possa specificare l'interfaccia del servizio. Ad esempio Services.AddService(typeof(IGraphicsDeviceManager), graphics);,. Quindi, durante il recupero del servizio, è possibile specificare l'interfaccia come tipo e trasmetterla alla sottoclasse scelta.
John Pollick,

@JohnPollick, per la prima domanda. Cerco di richiederlo sempre (perché potrebbe essere cambiato) ma se ho davvero bisogno di qualcosa in ogni frame, creo una variabile membro. Non ho molte statistiche sulle prestazioni oltre a questo, non è mai stato un collo di bottiglia per me. Il secondo, sì, sembra a posto :). E per il terzo. Questo è davvero il motivo per l'argomento tipo, tuttavia non dovresti mai prendere l'abitudine di trasferire i valori recuperati perché ciò distrugge la tua capacità di scambiare le classi come servizio. Se non desideri un IGraphicsDeviceManger ma un MyGDM, puoi creare una nuova interfaccia.
Roy T.

1
Oh, non ti ho visto anche lanciato. Ovviamente è in grado di inferire il tipo se lanci per primo :).
Roy T.

5

Quindi perché non trasformare queste istanze in Singleton? Bene, perché i Singleton sono cattivi perché hanno uno stato globale, impediscono i test e rendono il tuo design molto più fragile.

I singleton generalmente prendono molti tratti utili e li impacchettano in un terribile ibrido che ti dà molte cose che non vuoi insieme a qualsiasi cosa tu voglia. (Si trattava di caratteristiche "create su richiesta"? Ambito globale? Applicazione di almeno un'istanza? Divieto di più istanze?)

I localizzatori di servizi sono ugualmente considerati un anti-modello per molti perché invece di passare semplicemente la dipendenza a un oggetto, si passa un localizzatore di servizi (il Gioco) che accoppia quella classe con il resto dei servizi.

Non puoi evitare l'accoppiamento del tutto. Le cose usano altre cose e senza che il tuo programma non faccia nulla. Quindi l'unica vera domanda è a che livello è l'astrazione.

La maggior parte dei testi sull'orientamento agli oggetti fa una distinzione tra Composizione e Aggregazione. È importante conoscere la differenza concettuale tra qualcosa che possiedi e qualcosa che conosci. Sfortunatamente la maggior parte delle lingue moderne non ha una chiara distinzione qui, e un riferimento a un oggetto potrebbe significare una di queste cose. (Ironia della sorte, C ++ fa un lavoro migliore, se si utilizzano i vari tipi di puntatore intelligente.)

Un modo in cui è possibile chiarire composizione e aggregazione nel codice è utilizzare i servizi per oggetti aggregati. I servizi sono un modo per fornire accesso a cose che non possiedi, ma che puoi usare.

Allora perché i servizi sono consigliati in XNA e nello sviluppo di giochi?

Non penso che siano universalmente raccomandati nello sviluppo del gioco.

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.