Jak uniknąć wzorca singletonu dla Event Scheduler?


13

Chcę stworzyć harmonogram wydarzeń dla mojej gry, w zasadzie chcę mieć możliwość zaplanowania uruchomienia zdarzenia gry. Może to być wyzwalacz jednorazowy lub wyzwalacz okresowy (zdarzenie wyzwalające „E_BIG_EXPLOSION” co 5 sekund ...).

Kuszące jest myślenie, że może to być dobre miejsce do korzystania z Singletona, ale singletony mogą być całkiem złe i mają tendencję do rozprzestrzeniania się jak choroba ... więc staram się ich unikać za wszelką cenę.

Jaki projekt zaproponowałbyś, aby uniknąć użycia singletonu w tym przypadku?


Odpowiedzi:


12

Powinieneś mieć bardzo dobrze zdefiniowany zestaw interfejsów, które mogą transmitować lub odbierać wiadomości - podanie im odwołania do EventScheduler powinno być trywialne. Jeśli tak nie jest, lub jeśli uważasz, że to wymagałoby przekazania harmonogramu wydarzeń do „zbyt wielu” różnych typów, możesz mieć większy problem projektowy na rękach (rozwiązana zależność, której singletony mają tendencję do zaostrzania, a nie rozwiązywania ).

Pamiętaj, że chociaż technika przekazywania harmonogramu do potrzebnych interfejsów jest formą „ wstrzykiwania zależności ”, w tym przypadku nie wprowadza się nowej zależności. Jest to zależność, którą już masz w systemie, ale teraz czynisz ją jawną (w porównaniu z domyślną zależnością singletona). Zasadą jest, że wyraźne zależności są bardziej preferowane, ponieważ są bardziej samo-dokumentujące.

Zapewniasz sobie również większą elastyczność, oddzielając od siebie odbiorców harmonogramu zdarzeń (ponieważ nie wszyscy oni są koniecznie powiązani z tym samym harmonogramem), co może być przydatne do testowania lub symulacji lokalnych ustawień klient / serwer lub szeregu innych opcji - możesz nie potrzebować tych innych opcji, ale nie dołożyłeś starań, aby sztucznie się od nich ograniczyć, co jest plusem.

EDYCJA: Mam na myśli, gdy mówię o przekazywaniu harmonogramu, to: jeśli masz jakiś element gry, który jest odpowiedzialny za reagowanie na kolizję, prawdopodobnie jest on tworzony przez fabrykę reagowania na kolizję, która jest częścią twojej warstwy fizycznej. Jeśli zbudujesz fabrykę za pomocą instancji programu planującego, może ona przekazać tę instancję do wszystkich tworzonych przez nią obiektów odpowiadających, które mogą następnie wykorzystać ją do wywoływania zdarzeń (lub być może subskrybować inne zdarzenia).

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

To oczywiście strasznie wymyślony i uproszczony przykład, ponieważ nie wiem, jaki jest twój model obiektowy gry; ilustruje to jednak wyraźne uzależnienie od harmonogramu zdarzeń i pokazuje pewien potencjał do dalszego enkapsulacji (niekoniecznie trzeba by przekazywać responderom harmonogram, gdyby komunikowali się z systemem odpowiedzi na kolizję wyższego poziomu na tym samym poziomie koncepcyjnym, co fabryka, która poradziła sobie z problemami związanymi z wywoływaniem zdarzeń za pośrednictwem harmonogramu. To odizolowałoby każdą implementację odpowiadającego od szczegółów implementacji systemu wysyłania zdarzeń, takich jak które konkretne zdarzenie wywołać w przypadku kolizji, które może być idealne dla twojego systemu - - albo nie).


Dzięki za odpowiedź, myślałem o zastrzyku zależności. Byłoby bardzo miło, gdybyś mógł lepiej określić swoje rozwiązanie? (Pseudokod? Diagram?). Myślę, że podążam za twoim pomysłem, ale może to tylko moja interpretacja tego pojęcia.
Mr.Gando,

Trudno to zrobić w sposób przydatny, nie wiedząc, jakie klasy wysyłają / odbierają zdarzenia do harmonogramu.

W moim Engine, każdy podmiot Gra może mieć składnik „Event Dispatcher” przywiązany ...
Mr.Gando

7

Dyspozytor wydarzeń to jeden z tych przypadków, w których singleton nie jest najgorszym pomysłem na świecie, ale cieszę się, że próbujesz go uniknąć. Możesz znaleźć tutaj kilka pomysłów .


1
Dzięki !, za każdym razem, gdy tworzy się singleton, umiera Kociak;)
Mr.Gando

3

Staram się też unikać singletonów, ale istnieje kilka obiektów, które mają największy sens, ponieważ singletony są jednym z nich. Pomimo rantów, które słyszałem, singletony są z pewnością znacznie lepsze niż zmienne / funkcje globalne, ponieważ zawsze trzeba to celowo rozwiązać (w porównaniu do wartości globalnych po prostu magicznie pojawiających się z powietrza).

W końcu każdy nadawca i odbiorca wiadomości muszą mieć jakiś wspólny punkt przecięcia, a to jest o wiele lepiej, aby zachować swoje obiekty w izolowane poprzez posiadanie wspólnego singleton udostępnionego przez wszystko zamiast mieć każdego z nadawców wiadomości bezpośrednio wiedzieć na temat odbiorników komunikatów.

Chociaż jestem pewien, że można opracować inną architekturę dla twojego systemu zdarzeń, wydaje mi się, że marnowanie wysiłku na przemyślenie go jest marnowaniem, szczególnie gdy używanie systemu zdarzeń jest już dużym zyskiem, jeśli go nie używasz.

EDYCJA: Jeśli chodzi o konkretny przykład zdarzenia wybuchowego wysyłanego za pomocą okresowego wyzwalacza, prawdopodobnie spowodowałbym wysłanie zdarzeń do jakiegoś innego obiektu (takiego jak działo wieżowe lub cokolwiek powodującego te wybuchy), a nie w centralnym systemie zdarzeń. Jednak zdarzenia te byłyby nadal wysyłane do centralnego systemu wydarzeń.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.