A Microsoft.Xna.Framework.Game
classe 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 AudioComponent
para todas as classes e métodos que o exigem, basta passar sua Game
instâ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?
fonte
Respostas:
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.
fonte
return (T)Instance.GetService(typeof(T));
é.Service
sufixo redundante no final de cada método.AddService
método Services leva um tipo é para que você possa especificar a interface do serviço. Por exemploServices.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.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?)
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.
Eu não acho que eles sejam universalmente recomendados no desenvolvimento de jogos.
fonte