Як уникнути одинарного шаблону для планувальника подій?


13

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

Заманливо думати, що це може бути хорошим місцем для використання Сингтона, але одиночні можуть бути дуже злими, і вони, як правило, поширюються як хвороба ... тому я намагаюся їх уникнути будь-якою ціною.

Яку конструкцію ви б запропонували уникнути використання одноразового в цьому випадку?


Дивіться цю відповідь на замінниках одиночних
BlueRaja - Danny Pflughoeft

Відповіді:


12

У вас повинен бути дуже чітко визначений набір інтерфейсів, яким дозволяється передавати або приймати повідомлення - надання їм посилання на EventScheduler має бути тривіальним. Якщо це не так, або якщо ви вважаєте, що це передбачає перенесення планувальника подій до "занадто багато" різних типів, то у вас може виникнути більша проблема дизайну (руйнівна залежність, яку одинаки, як правило, посилюють, а не вирішує ).

Пам’ятайте, що, хоча техніка передачі планувальника інтерфейсам, які йому потрібні, є формою " введення залежності ", ви в цьому випадку не вводите нову залежність. Це залежність, яку ви вже маєте в системі, але тепер ви робите її явною (проти неявної залежності сингтона). Як правило, явні залежності є більш переважними, оскільки вони більш самодокументовані.

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

EDIT: Все, що я маю на увазі, коли я говорю про передачу планувальника навколо, це таке: якщо у вас є якийсь ігровий компонент, який відповідає за реагування на зіткнення, він, ймовірно, створюється через деяку фабрику реагування на зіткнення, яка є частиною вашого рівня фізики. Якщо ви сконструюєте фабрику з екземпляром планувальника, то він може передавати цей екземпляр будь-яким створеним ним респондентам, які потім можуть використовувати його для піднесення подій (або, можливо, підписатися на інші події).

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

Це, очевидно, жахливо надуманий і спрощений приклад, оскільки я не знаю, що таке ваша об'єктна ігрова модель; Однак це ілюструє виразність залежності від планувальника подій явною та показує певний потенціал для подальшої інкапсуляції (вам не обов'язково потрібно передавати відповіді планувальнику, якби вони повідомлялися через систему відповідей вищого рівня на зіткнення на тому самому концептуальному рівні, що і фабрика, яка займалася гайками та болтами подій підняття за допомогою планувальника. Це дозволить виокремити реалізацію кожного конкретного респондента від деталей про реалізацію системи диспетчеризації подій, наприклад, яку конкретну подію викликати при зіткненні, яка може бути ідеальною для вашої системи - - чи ні).


Дякую за вашу відповідь, я думав про ін'єкцію залежності. Було б дуже приємно, якби ви могли трохи уточнити своє рішення? (Псевдокод? Діаграма?). Я думаю, що я дотримуюся вашої ідеї, але, можливо, це лише моя власна інтерпретація концепції.
Mr.Gando

Це важко зробити так, щоб це було корисно, не знаючи, які твої класи надсилають / отримують події до планувальника.

У моєму двигуні будь-яка організація гри може мати доданий компонент "Диспетчер подій" ...
Mr.Gando

7

Диспетчер подій - один із тих випадків, коли сингтон - не найгірша ідея у світі, але я аплодую вам за те, що намагаєтесь цього уникнути. Ви могли б знайти деякі ідеї тут .


1
Дякую !, щоразу, коли
одиночка

3

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

Зрештою, кожен відправник та одержувач повідомлень повинен мати якусь спільну точку перетину, і набагато краще, щоб ваші об'єкти були роз'єднані, маючи спільний синглтон, який ділиться всім, а не кожен ваш передавач повідомлень безпосередньо знає про приймачів повідомлень.

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

EDIT: Що стосується вашого конкретного прикладу вибухової події, що надсилається періодично, то, мабуть, події будуть розіслані в якомусь іншому об'єкті (як, наприклад, у башти або у тому, що спричинює ці вибухи), а не в центральній системі подій. Однак ці події все одно пересилатимуться до центральної системи подій.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.