Estou fazendo um jogo no as3 usando o flash develop e o flash cs5. Tudo é orientado a objetos. Eu estava pensando, se eu deveria ter uma classe "gateway" que possua uma referência de propriedade a todas as instanciações de outras classes, e apenas passo essa classe de gateway para novos objetos, para que eles tenham acesso a todas as classes. Igual a:
var block:Block=newBlock(gateway);//In the block class:this.gateway.player.setHealth(100);//Or:this.gateway.input.lock();
É como um padrão singleton ou algo assim? Devo fazer isso?
Objetos de contexto ajudam no teste, porque você pode passar contextos simulados para as funções que deseja testar. Singletons impedem isso, porque para zombar de singletons você precisa torná-los não singletons.
Objetos de contexto tornam seu "estado global" explícito e, portanto, mais fácil de raciocinar. Se uma função não aceita um objeto de contexto, você sabe que não usa nenhum estado de contexto global. Você não tem essa garantia com singletons ou variáveis globais.
Objetos de contexto são muito mais lentos se você não os usar, porque você adiciona outro parâmetro a todas as suas chamadas de função. Eles podem ser mais rápidos que os globais se você os usar e são quase sempre mais rápidos que os singletons.
Objetos de contexto são mais fáceis de implementar; geralmente eles vivem na pilha ou pilha de uma maneira normal. Singletons têm problemas complicados que envolvem threading em vários idiomas.
Então não, isso não é um singleton, é muito melhor que um singleton.
No entanto, você ainda está repassando um upload de estado - o fato de manter tudo em uma única variável local torna mais explícito, mas ainda cria grande confusão de preocupações . Lembre-se da regra de uma responsabilidade . Faz algum sentido que exista um contexto que possua o player e o nível atual - eles estão relacionados - mas por que o mesmo contexto possui sua entrada no teclado?
Considere diferentes níveis de contextos, por exemplo:
GameplayContext - possui o jogador, inimigos, a geometria do nível, etc.
InputContext - possui alças de teclado e mouse, eventos de entrada etc.
GraphicsContext - possui texturas, o identificador de janela, etc.
GlobalContext - possui um GameplayContext, um GraphicsContext e um InputContext. É aqui que você deseja aplicar o padrão do localizador de serviço para poder trocar alguns contextos por outros, conforme necessário. E talvez, para iteração e teste rápidos, isso deva estar em uma variável global real - basta perceber que sempre que você o usa, você está acumulando dívidas de tecnologia .
Esses contextos ainda conflitam um pouco as preocupações - talvez algum manipulador de eventos use um GameplayContext e realmente precise apenas do jogador - mas as responsabilidades são claramente definidas. Você sabe que algo que usa um GameplayContext não carrega uma textura; algo usando um InputContext não pode matar um jogador.
+1 boa resposta. No entanto, algumas das preocupações com velocidade ou encadeamento não se aplicam realmente a este contexto (o ActionScript3 não suporta encadeamento e muitos mecanismos de aprimoramento de velocidade que funcionam em C ++ não se aplicam ao usar o AS3).
bummzack
Eu não sei muito sobre o AS3VM, mas nas linguagens mais dinâmicas, o custo de passar / receber / usar um local ainda é mais rápido (pesquisa de matriz) do que o custo de procurar uma pesquisa global (hash) e muito mais rápida do que chamando uma função (craploads de coisas) para chegar lá. Então, acho que esse conselho ainda se aplica.
0
Isso não se parece com o padrão Singleton. Pelo que entendi, você está passando um objeto com referências a objetos importantes do jogo para todas as suas instâncias.
Se esse fosse o padrão Singleton, você teria:
AudioManager.getInstance().playSound(XY);
Considerando que, no seu caso, você pode ter:
this.gateway.getAudioManager().playSound(XY);
Parece basicamente o mesmo, mas realmente não é. Se você deseja substituir AudioManagerpor um novo (classe estendida) como ExtendedAudioManager, você bateu em uma parede usando o padrão Singleton. Sua abordagem de gateway lidará com isso muito bem.
A desvantagem da sua abordagem é que você terá que passar por gatewaytodos os lugares. O padrão do localizador de serviço (proposto por Joe Wreschnig neste tópico) parece um bom substituto para o seu "padrão de gateway".
Às vezes, é melhor executar apenas o método simples e direto, em vez de projetar demais as coisas. Especialmente quando é um projeto pequeno ou um protótipo. Talvez você possa fazer disso gatewayalgum tipo de variável global. Game.gatewaye corra com ele.
A maioria das soluções para esse problema, incluindo o padrão Singleton, envolve o uso de variáveis estáticas. Se você tiver apenas um jogador, poderá fazer com que o Player seja uma classe singleton, o que significa que você pode acessar a instância do Player por meio de Player.currentPlayer. Muitas pessoas se enfurecem contra os Singletons, no entanto. Você também pode ter um ResourceManager ou classe similar que contenha referências estáticas para várias variáveis globais úteis ou bastante danadas do mundo. No seu código, você também pode tornar as variáveis do "Gateway" estaticamente acessíveis, em vez de aumentar o seu código, passando-o por toda parte.
A questão mudou substancialmente desde que eu fiz essa resposta, o suficiente para que não pareça valer a pena editá-la.
Gregory Avery-Weir
2
Além do título, nada mudou na questão.
bummzack
11
O que? Nada mudou além do título. -1
AttackingHobo
Eu acho que estava pensando no título aqui; Lembro que o título original era algo como "Como devo fazer isso?" É totalmente possível que eu tenha interpretado mal o título / pergunta inicial quando fiz a resposta.
Isso não se parece com o padrão Singleton. Pelo que entendi, você está passando um objeto com referências a objetos importantes do jogo para todas as suas instâncias.
Se esse fosse o padrão Singleton, você teria:
Considerando que, no seu caso, você pode ter:
Parece basicamente o mesmo, mas realmente não é. Se você deseja substituir
AudioManager
por um novo (classe estendida) comoExtendedAudioManager
, você bateu em uma parede usando o padrão Singleton. Sua abordagem de gateway lidará com isso muito bem.A desvantagem da sua abordagem é que você terá que passar por
gateway
todos os lugares. O padrão do localizador de serviço (proposto por Joe Wreschnig neste tópico) parece um bom substituto para o seu "padrão de gateway".Às vezes, é melhor executar apenas o método simples e direto, em vez de projetar demais as coisas. Especialmente quando é um projeto pequeno ou um protótipo. Talvez você possa fazer disso
gateway
algum tipo de variável global.Game.gateway
e corra com ele.fonte
A maioria das soluções para esse problema, incluindo o padrão Singleton, envolve o uso de variáveis estáticas. Se você tiver apenas um jogador, poderá fazer com que o Player seja uma classe singleton, o que significa que você pode acessar a instância do Player por meio de Player.currentPlayer. Muitas pessoas se enfurecem contra os Singletons, no entanto. Você também pode ter um ResourceManager ou classe similar que contenha referências estáticas para várias variáveis globais úteis ou bastante danadas do mundo. No seu código, você também pode tornar as variáveis do "Gateway" estaticamente acessíveis, em vez de aumentar o seu código, passando-o por toda parte.
fonte