Como evitar o padrão singleton para o Event Scheduler?


13

Quero criar um agendador de eventos para o meu jogo. Quero basicamente poder agendar o acionamento de um evento de jogo. Pode ser um disparador único ou periódico (evento de disparo "E_BIG_EXPLOSION" em 5 segundos ...).

É tentador pensar que este pode ser um bom lugar para usar um Singleton, mas os singletons podem ser muito maus e tendem a se espalhar como uma doença ... então, tento evitá-los a todo custo.

Que projeto você proporia para evitar o uso de singleton neste caso?


Veja esta resposta em alternativas aos singletons
BlueRaja - Danny Pflughoeft 4/11/11

Respostas:


12

Você deve ter um conjunto muito bem definido de interfaces com permissão para transmitir ou receber mensagens - fornecer uma referência a um EventScheduler deve ser trivial. Se não estiver, ou se você acha que isso envolveria passar o agendador de eventos para "muitos" tipos distintos, você pode ter um problema maior de design em suas mãos (uma dependência promíscua, que os singletons tendem a exacerbar, não resolver) )

Lembre-se de que, embora a técnica de passar o agendador para as interfaces necessárias seja uma forma de " injeção de dependência ", nesse caso, você não está injetando uma nova dependência. Essa é uma dependência que você já possui no sistema, mas agora a torna explícita (versus a dependência implícita de um singleton). Como regra geral, dependências explícitas são mais preferíveis, pois são mais auto-documentadas.

Você também oferece mais flexibilidade, dissociando os consumidores do agendamento de eventos (já que nem todos estão necessariamente vinculados ao mesmo agendador), o que pode ser útil para testar ou simular configurações locais de cliente / servidor ou várias outras opções. - você pode não precisar dessas outras opções, mas não fez nenhum esforço para se restringir artificialmente a elas, o que é uma vantagem.

EDIT: Tudo o que quero dizer quando falo sobre passar o agendador é o seguinte: se você tem algum componente do jogo responsável por responder à colisão, provavelmente é criado através de alguma fábrica de respondedores de colisão que faz parte da sua camada de física. Se você construir a fábrica com uma instância do agendador, poderá passá-la para todos os respondentes criados, que poderão utilizá-la para gerar eventos (ou talvez se inscrever em outros eventos).

class CollisionResponderFactory {
  public CollisionResponderFactory (EventScheduler scheduler) {
     this.scheduler = scheduler;
  }

  CollisionResponder CreateResponder() {
    return new CollisionResponder(scheduler);
  }

  EventScheduler scheduler;
}

class CollisionResponder {
  public CollisionResponder (EventScheduler scheduler) {
    this.scheduler = scheduler;
  }

  public void OnCollision(GameObject a, GameObject b) {
    if(a.IsBullet) {
      scheduler.RaiseEvent(E_BIG_EXPLOSION);
    }
  }

  EventScheduler scheduler;
}

Este é obviamente um exemplo terrivelmente artificial e simplificado, pois não sei qual é o seu modelo de objeto de jogo; no entanto, ilustra explicitando a dependência do agendador de eventos e mostra algum potencial para encapsulamento adicional (você não precisaria necessariamente passar o respondedor para o agendador se eles se comunicassem através de um sistema de resposta de colisão de nível superior no mesmo nível conceitual que o fábrica que lidava com as porcas e os parafusos de aumento de eventos por meio do agendador.Isso isolaria cada implementação de respondedor individual dos detalhes de implementação do sistema de envio de eventos, como qual evento específico deve ocorrer em colisão, o que pode ser ideal para o seu sistema - - ou não).


Obrigado pela sua resposta, pensei em injeção de dependência. Seria muito bom se você pudesse especificar sua solução um pouco melhor? (Pseudo-código? Diagrama?). Acho que sigo sua ideia, mas talvez seja apenas minha própria interpretação do conceito.
Mr.Gando 5/08/11

É difícil fazer isso de uma maneira que seja útil sem saber quais classes suas enviam / recebem eventos para o agendador.

No meu mecanismo, qualquer entidade de jogo pode ter um componente "Event Dispatcher" anexado ...
Mr.Gando

7

Um despachante de eventos é um daqueles casos em que um singleton não é a pior ideia do mundo, mas eu o aplaudo por tentar evitá-lo. Você pode encontrar algumas idéias aqui .


1
Obrigado !, cada vez que um singleton é criado, um Kitten Dies;)
Mr.Gando

3

Eu também evito singletons, mas existem alguns objetos que fazem mais sentido, pois singletons e um sistema central de mensagens é um deles. Apesar dos protestos que ouvi, os singletons são certamente muito melhores do que as variáveis ​​/ funções globais, porque você sempre precisa abordá-lo deliberadamente (em comparação com valores globais apenas aparecendo magicamente do nada).

No final, todo remetente e destinatário da mensagem deve ter algum ponto comum de interseção, e é muito melhor manter seus objetos dissociados, com um singleton comum compartilhado por tudo, em vez de cada um dos seus remetentes saber diretamente sobre os destinatários da mensagem.

Embora eu tenha certeza de que alguma outra arquitetura poderia ser criada para o seu sistema de eventos, para mim parece um desperdício de esforço pensar demais, especialmente quando usar um sistema de eventos já é uma grande vitória sobre não usá-lo.

Edição: Quanto ao seu exemplo específico de um evento de explosão despachado em um gatilho periódico, eu provavelmente teria os eventos despachados em algum outro objeto (como a pistola da torre ou o que está causando essas explosões) e não no sistema central de eventos. No entanto, esses eventos ainda seriam despachados para o sistema central de eventos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.