Agora não consigo ver nada imediatamente errado com isso ou com qualquer coisa que possa causar problemas, mas apenas comecei a usar classes estáticas. Alguém mais experiente vê alguma razão gigante por que essa é uma má ideia?
Quando você tem um novo martelo brilhante, todo problema parece um prego.
Em geral, não há nada de errado com classes e / ou métodos estáticos, se usados corretamente (para itens que não possuem ou dependem do estado por instância). No entanto, no seu caso, você os está usando incorretamente para ocultar uma dependência por instância, confundindo isso com a remoção da dependência. Parece também que você está expondo os detalhes de implementação da Game1
classe, o que geralmente também é ruim.
Aqui está o ponto crucial do seu problema:
... se eu estiver dentro AnimalHandler
e quiser verificar se um bloco pode ser percorrido a partir de
TileHandler
então, isso causa problemas ou eu tenho que passar uma lista de blocos que podem ser percorridos AnimalHandler
, o que eu prefiro não fazer.
Ignorando a possibilidade de que AnimalHandler
precisar desses blocos possa ser um projeto ruim (com os nomes que você escolheu, é difícil contar os detalhes dessas classes) no momento ... se AnimalHandler
precisar de uma lista de blocos acessíveis, então precisará de uma lista de telhas tranquilas. Geralmente, é melhor tornar as dependências mais explícitas do que menos , pois isso torna o código mais auto-documentado. Ao passar a lista diretamente para AnimalHandler
, você explicita o fato de que ela precisa dessa lista. Se você tornar tudo estático e público para acessar a lista estática mantida em outra parte do código, tudo o que você faz é ocultar a dependência sem realmente resolvê-la ou removê-la.
Para um jogo pequeno que não precisa ser escalado, isso não será um problema, por si só, mas pode levar você a seguir um mau hábito, portanto, considere não fazê-lo. No mínimo, lembre-se disso para o próximo projeto em que você trabalha.
A razão pela qual chamar o TileHandler em um contexto estático não é o melhor design possível, é o fato de associar componentes do seu design que poderiam ser dissociados.
Se você optar por ter mais de um TileHandler no futuro, precisará fazer muito trabalho para acomodar essa alteração.
Se você optar por remover o TileHandler, precisará fazer muito trabalho para acomodar essa alteração.
Suponha que você construa um nível / zona diferente no futuro, que lide com blocos de maneira diferente do seu TileHandler atual. Então você precisa ter uma maneira de especificar o método de manipulação de lado a lado a ser usado ou precisa chamar um manipulador diferente.
Se o TileHandler foi passado como um parâmetro para objetos que o utilizam, você pode simplesmente passar um diferente na próxima vez ou definir um manipulador de mosaico diferente nos objetos que o usam posteriormente.
Pessoalmente, acesso muitas coisas nos meus jogos XNA a partir de um contexto estático e presumo que nunca terei mais que um deles.
Se você quiser reutilizar o código do mecanismo de jogo no próximo jogo, provavelmente precisará reescrever muitas das coisas que você escreveu atualmente como estáticas.
Em resumo:
A favor de não usar o contexto estático:
Passar objetos como parâmetros, tanto quanto possível, dissocia elementos do jogo e permite modificá-los / reutilizá-los para os projetos atuais ou futuros com mais facilidade. Ele também permite que você gerencie a complexidade de grandes quantidades de código um pouco mais fácil (pense em ter centenas de gerenciadores estáticos em sua classe de jogo, em um grande jogo).
A favor do contexto estático:
Declarar e acessar objetos de um contexto estático facilita a criação de pequenos jogos que não exigem centenas de gerenciadores de estática. Simplifica muitos métodos e construtores, não exigindo um ou mais parâmetros extras que são acessados estaticamente.
fonte
Não acho que seja uma má ideia para um jogo simples, mas você também pode dar uma olhada em http://www.nuclex.org/articles/4-architecture/6-game-components-and-game-services para uma idéia melhor de como criar componentes de jogos intercomunicantes
fonte
Coisas como TileHandler e AnimalHandler Eu colocaria um nível mais alto na tela de um jogo. Sua tela de título precisa de acesso ao TileHandler e é inicializada quando o jogo é carregado pela primeira vez? Provavelmente não.
Confira a amostra XNA State Management . Tem muito código lá, mas basicamente o jogo base apenas inicializa uma pilha de estados (ou telas) do jogo. Cada tela é bastante independente das outras e funciona como uma versão simplificada do próprio jogo. Seu PlayScreen pode ter membros estáticos, para que eles sejam acessíveis aos componentes do PlayScreen.
No jogo base, eu uso algumas estatísticas, mas são coisas de nível muito baixo, como os leitores InputHelper, Log ou Config. Eles são bastante comuns em todos os jogos, para que o mecanismo básico possa ser transportado rápida e facilmente. As telas são onde a lógica real do jogo acontece. Resposta longa por muito tempo - não, não acho que seja uma má idéia em teoria, apenas tome cuidado com o que você faz estática. Depois que você faz algo estático, é uma tremenda quantidade de trabalho se você mudar de idéia.
fonte
Os pontos levantados aqui são todos bons. Na minha experiência (que reconhecidamente é mais voltada para aplicativos de negócios do que jogos), há ótimos usos para membros e classes estáticas e eu os usei muitas vezes. Descobri que, à medida que os requisitos e a complexidade aumentam, acabo reciclando essas classes estáticas e convertendo-as em classes de instância e começo a distribuí-las.
O ponto que eu gostaria de destacar é que, se o uso de uma classe estática o ajudar a finalizar o jogo, siga em frente, mas faça as coisas certas: implemente uma interface ou classe base para que seja mais fácil extraí-lo e convertê-lo para uma classe de instância mais tarde.
Um grama de prevenção vale um quilo de cura, portanto, verifique se a classe estática não o prende, o que dificulta a mudança. É muito fácil refatorar um método usando uma classe estática que implementa uma interface, para que ele aceite um novo parâmetro de interface e use essa interface em vez da referência de classe estática.
fonte
Sim, geralmente é sempre uma má ideia.
Transformar objetos que contêm dados alterados (ou seja, qualquer coisa além de constantes somente leitura e tabelas de pesquisa) em classes estáticas é onde o bom design entra em ação.
Promove dependências aleatórias que eliminam a modularidade e atrapalham a reutilização de código. Suponha que você queira escrever um editor para o seu jogo - de repente você terá muitas aulas chorando por um
Game1
que não possa ser movida facilmente para uma biblioteca compartilhada.Seu código se torna não testável. O teste de unidade funciona isolando classes individuais das demais, zombando ou simulando suas dependências (que devem ser mantidas o mínimo possível). Qualquer classe estática é uma responsabilidade, pois pode ser acessada a qualquer momento, transportar o estado em vários testes ou exigir que seja inicializada antes que os testes possam ter êxito.
Oculta dependências. Assim como o antipadrão do provedor de serviços (também empregado pelo XNA, Game.Services), suas classes podem escolher dependências que você não vê externamente.
Essa abordagem se torna especialmente venenosa se alguém combinar classes estáticas com chamadas de trem de carga (coisas como é o que ocorre
Game.Instance.ActorManager.Enemies.FindInRange(10)
por causa dos símbolos encadeados em vagões), onde componentes repentinamente não apenas exigem umaGame
classe, mas uma com umaInstance
propriedade estática que retorna algo com umaActorManager
propriedade que tem umEnemies
propriedade que retorna um objeto com umFindInRange()
métodoA única desculpa que eu aceitaria para escrever classes estáticas mutáveis seria a que ainda está aprendendo e ainda não tem a capacidade de aplicar consistentemente um bom design e um olho treinado para detectar más escolhas ainda.
fonte