Как избежать одноэлементного шаблона для Event Scheduler?

13

Я хочу создать планировщик событий для своей игры, я в основном хочу иметь возможность планировать запуск игрового события. Это может быть одноразовый запуск или периодический запуск (событие запуска "E_BIG_EXPLOSION" на основе 5 секунд ...).

Соблазнительно думать, что это может быть хорошим местом для использования Синглтона, но синглтоны могут быть довольно злыми, и они имеют тенденцию распространяться как болезнь ... поэтому я стараюсь избегать их любой ценой.

Какой дизайн вы бы предложили, чтобы избежать использования синглтона в этом случае?

Mr.Gando
источник
См. Этот ответ на альтернативы синглтонам
BlueRaja - Дэнни Pflughoeft

Ответы:

12

У вас должен быть очень четко определенный набор интерфейсов, которым разрешено передавать или получать сообщения - дать им ссылку на EventScheduler должно быть тривиально. Если это не так, или если вам кажется, что это потребует передачи планировщика событий «слишком большому количеству» различных типов, то у вас может возникнуть проблема с большими проектами (неразборчивая зависимость, которую синглеты имеют тенденцию усугублять, а не решать ).

Помните, что хотя техника передачи планировщика нужным интерфейсам является формой « внедрения зависимостей », в этом случае вы не внедряете новую зависимость. Это зависимость, которая у вас уже есть в системе, но теперь вы делаете ее явной (в отличие от неявной зависимости синглтона). Как правило, явные зависимости более предпочтительны, поскольку они более самодокументированы.

Вы также позволяете себе больше гибкости, отделяя потребителей планирования событий друг от друга (поскольку они не обязательно связаны с одним и тем же планировщиком), что может быть полезно для тестирования или моделирования локальных настроек клиент / сервер или ряда других параметров. - вам могут не понадобиться эти другие варианты, но вы не приложили усилий, чтобы искусственно ограничить себя от них, что является плюсом.

РЕДАКТИРОВАТЬ: все, что я имею в виду, когда я говорю о передаче планировщика, это: если у вас есть какой-то игровой компонент, отвечающий за реагирование на столкновение, он, вероятно, создается с помощью какой-то фабрики по реагированию на столкновения, которая является частью вашего физического уровня. Если вы создаете фабрику с помощью экземпляра планировщика, он может затем передать этот экземпляр любым созданным им респондентам, которые затем могут использовать его для создания событий (или, возможно, подписки на другие события).

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;
}

Это, очевидно, ужасно надуманный и упрощенный пример, поскольку я не знаю, какова ваша игровая объектная модель; однако он иллюстрирует явную зависимость от планировщика событий и показывает некоторый потенциал для дальнейшей инкапсуляции (вам не обязательно передавать респондерам планировщик, если они взаимодействуют с системой реагирования на столкновения более высокого уровня на том же концептуальном уровне, что и Фабрика, которая имела дело с основными моментами создания событий через планировщик, что изолировало бы каждую отдельную реализацию респондента от подробностей реализации системы диспетчеризации событий, таких как конкретное событие, возникающее при столкновении, которое может быть идеальным для вашей системы - - или не).


источник
Спасибо за ваш ответ, я подумал о внедрении зависимости. Было бы очень хорошо, если бы вы могли указать свое решение немного лучше? (Псевдокод? Диаграмма?). Я думаю, что следую вашей идее, но, возможно, это просто моя собственная интерпретация концепции.
Гандо
Трудно сделать это удобным способом, не зная, какие ваши классы отправляют / получают события в планировщике.
В моем движке к любому игровому объекту может быть прикреплен компонент «Диспетчер событий» ...
игровому объекту
7

Диспетчер событий - один из тех случаев, когда синглтон не самая плохая идея в мире, но я приветствую вас за то, что вы пытались избежать этого. Вы можете найти некоторые идеи здесь .

необычайно щедрый
источник
1
Спасибо !, каждый раз, когда создается синглтон, котенок умирает;)
Mr.Gando
3

Я также склонен избегать синглетонов, но есть несколько объектов, которые имеют наибольшее значение, так как центральная система обмена сообщениями является одним из них. Несмотря на то, что я слышал суету, синглтоны, безусловно, намного лучше, чем глобальные переменные / функции, потому что вы всегда должны сознательно обращаться к ним (в отличие от глобальных значений, просто волшебно появляющихся из воздуха).

В конце концов , каждый отправитель и получатель должен иметь некоторые общую точку пересечения, и гораздо лучше отделить ваши объекты, используя общий синглтон, общий для всех, чем чтобы каждый из ваших отправителей сообщения непосредственно знал о получателях сообщения.

Хотя я уверен, что для вашей системы событий может быть разработана какая-то другая архитектура, мне кажется, что ее переосмысление кажется пустой тратой усилий, особенно когда использование системы событий уже является большой победой над ее использованием.

РЕДАКТИРОВАТЬ: Что касается вашего конкретного примера события взрыва, отправляемого по периодическому триггеру, я бы, вероятно, отправил события в каком-то другом объекте (например, турель или любой другой объект, вызывающий эти взрывы), а не в центральной системе событий. Однако эти события все равно будут отправлены в центральную систему событий.

jhocking
источник