Qual é a diferença entre XNA Game Services e variáveis ​​globais glorificadas?

10

A Microsoft.Xna.Framework.Gameclasse possui uma propriedade Services que permite ao programador adicionar um serviço ao jogo, fornecendo o tipo da classe e uma instância da classe ao método Add.

Agora, em vez de passar um AudioComponentpara todas as classes e métodos que o exigem, basta passar sua Gameinstância e procurar o serviço. ( Localizador de serviço )

Agora, como os jogos têm muitos serviços (GraphicsDevice, SceneGraph, AudioComponent, EffectsManager etc.), agora você estará basicamente passando o Game para tudo.

Então, por que não apenas tornar essas instâncias um Singleton? Bem, porque Singletons são ruins porque têm um estado global, impedem testes e tornam seu design muito mais frágil. Os localizadores de serviço são igualmente considerados um antipadrão para muitos, porque, em vez de apenas passar a dependência para um objeto, você passa um localizador de serviço (o Jogo) que combina essa classe com o restante dos serviços.

Então, por que os Serviços são recomendados no XNA e no desenvolvimento de jogos? É porque os jogos são diferentes dos programas regulares e estão altamente interligados com seus componentes e ter que passar por todos os componentes necessários para o funcionamento de uma classe seria altamente complicado? Os serviços de jogos são um mal necessário no design de jogos? Existem alternativas que não envolvam longas listas de parâmetros e acoplamentos?

John Pollick
fonte
3
"Os localizadores de serviço são igualmente considerados um anti-padrão para muitos" - [citação necessária]. Obviamente, usá-los onde você não precisa deles é ruim - o que acontece com todas as construções de software -, mas eu nunca ouvi os localizadores de serviço chamados de antipadrão. (Por outro lado, eu também tentar programadores evitar que passam a maior parte de seu tempo discutindo as últimas minúcias padrão.)
@JoeWreschnig embora eu concordo com você que eu fiz alguma escavação e encontrei este: blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx
Roy T.
2
Sim, mas esse cara está vendendo um livro sobre o uso de DI; obviamente ele não quer que você use algo simples, então você não comprará o livro dele! (Em toda a seriedade, o artigo DI / SL original de Fowler cobriu este tema exato - martinfowler.com/articles/... - e blogue discurso daquele cara não acrescenta nada à discussão.)
Eu gostaria de poder marcar esse link que você acabou de postar de Martin Fowler como resposta (embora não seja a minha pergunta) #
217 Roy T. Roy

Respostas:

6

Eu não acho que todos concordam que os localizadores de serviço são ruins. Os Localizadores de Serviço fornecem uma maneira de dissociar funcionalidades importantes que todos precisam de sua implementação real. Os localizadores de serviço também fornecem uma maneira de trocar serviços em tempo de execução. Além disso, não acho que seja necessário passar o localizador de serviço por toda parte. Eu acho que você pode acessá-lo de qualquer lugar. Enquanto uma classe de jogo com globais precisaria ser passada cerca de mil vezes por quadro (o que causaria um desempenho ruim).

Para fazer a diferença entre o localizador de serviço e uma classe com globais um pouco mais clara, considere o seguinte exemplo:

Estou fazendo um jogo e uso um objeto de classe gameA que possui uma variável global: o carregador de conteúdo. Agora, no meu próximo jogo, não quero usar a classe gameA, mas criar uma nova classe gameB. Agora tenho que adicionar novamente as globais de gameA ao gameB, que é um trabalho extra. Também fica difícil configurar o tipo de carregador de conteúdo que eu quero. Digamos que eu tenho um jogo que roda tanto no PC quanto no XBOX. No PC, quero um carregador de conteúdo que também possa abrir uma caixa de diálogo 'abrir arquivo'. Enquanto no XBOX eu definitivamente não quero isso. Por ter um arquivo de configuração, eu posso, até a metade do jogo, mudar facilmente o carregador de conteúdo, mesmo de outro lugar que não seja da classe gameA, sem tornar públicas as globais do gameA.

Agora considere que estou usando um localizador de serviço. Eu sempre posso continuar usando. E até que tipo de serviços existem podem ser diferentes o tempo todo. Também é verdade que eu nem me importo com a implementação deles, desde que eles tenham uma interface comum. (Embora eu possa usar isso em um gamA como a classe também).

De qualquer forma, acho que você encontrará os serviços de jogos bastante úteis. Todo mundo que eu conheço usa. Para ajudá-lo um pouco mais. Criei uma pequena classe auxiliar em torno de serviços de jogos, para que você possa fazer um pouco menos de conversão o tempo todo: http://roy-t.nl/index.php/2010/08/25/xna-accessing-contentmanager - e - dispositivo gráfico - em qualquer lugar a qualquer momento - o servidor de jogos / eu o uso bastante.

Roy T.
fonte
Obrigado pela resposta. Em uma classe que exigiria um serviço, você normalmente apenas solicita a classe GameServices para o serviço sempre que necessário, ou cria uma variável de membro na classe e solicita o serviço apenas no construtor? Suponho que pergunto o quão lento return (T)Instance.GetService(typeof(T));é.
John Pollick
Além disso, o que você acha dessa implementação da classe GameServices? Eu removi o singleton desnecessário porque ele não tinha nenhum recurso que a abstração ainda não tivesse. Além disso, removi o Servicesufixo redundante no final de cada método.
John Pollick
Além disso, acho que a razão pela qual o AddServicemétodo Services leva um tipo é para que você possa especificar a interface do serviço. Por exemplo Services.AddService(typeof(IGraphicsDeviceManager), graphics);,. Em seguida, ao recuperar o serviço, você pode especificar a interface como o tipo e convertê-la na subclasse escolhida.
John Pollick
@JohnPollick, para a primeira pergunta. Eu tento sempre solicitá-lo (porque poderia ter mudado), mas se eu realmente precisar de algo em cada quadro, crio uma variável de membro. Não tenho muitas estatísticas de desempenho além de nunca ter sido um gargalo para mim. O segundo, sim, parece bom :). E para o terceiro. Essa é realmente a razão do argumento de tipo, no entanto, você nunca deve criar o hábito de baixar valores recuperados porque isso destrói sua capacidade de trocar de classe como serviço. Se você não deseja um IGraphicsDeviceManger, mas um MyGDM, crie uma nova interface.
Roy T.
1
Oh, eu não vi você também elenco. Claro que é possível inferir o tipo se você lançar primeiro :).
Roy T.
5

Então, por que não apenas tornar essas instâncias um Singleton? Bem, porque Singletons são ruins porque têm um estado global, impedem testes e tornam seu design muito mais frágil.

Os singletons geralmente pegam muitas características úteis e as agrupam em um híbrido terrível que oferece várias coisas que você não deseja, juntamente com o que você quiser. (Foram as características de "criação sob demanda"? Escopo global? Aplicação de pelo menos uma instância? Proibição de várias instâncias?)

Os localizadores de serviço são igualmente considerados um antipadrão para muitos, porque, em vez de apenas passar a dependência para um objeto, você passa um localizador de serviço (o Jogo) que combina essa classe com o restante dos serviços.

Você não pode evitar o acoplamento completamente. As coisas usam outras e sem isso seu programa não faz nada. Portanto, a única questão real é em que nível de abstração está.

A maioria dos textos sobre orientação a objetos faz uma distinção entre Composição e Agregação. É importante conhecer a diferença conceitual entre algo que você possui e algo que você conhece. Infelizmente, a maioria das linguagens modernas não tem uma distinção clara aqui, e uma referência a um objeto pode significar uma dessas coisas. (Ironicamente, o C ++ faz um trabalho melhor, se você usar os vários tipos de ponteiros inteligentes.)

Uma maneira em que você pode fazer composição e agregação claro em seu código é usando serviços para objetos agregados. Os serviços são uma maneira de fornecer acesso a coisas que você não possui, mas que você pode usar.

Então, por que os Serviços são recomendados no XNA e no desenvolvimento de jogos?

Eu não acho que eles sejam universalmente recomendados no desenvolvimento de jogos.

Kylotan
fonte