Допустим, у нас есть Observer и много-много разных событий (сотни). Стандартный Observer, описанный в википедии предлагает их различать по строковому идентификатору. Можно вспомнить, что мы хотим пользоваться всеми возможностями IDE и ввести какой-нибудь Enum вместо строкового идентификатора, но я заметил, что в результате метод Update раздувается до приблизительно такого свича:
void Update (Event e) {
switch (e.type) {
case EventType.Move:
OnMove( (MoveEvent) e );
break;
// ...
case EventType.Build:
OnBuild( (BuildEvent) e );
break;
}
}
В результате метод раздувается до офигенно большого свитча, который только и делает, что вызывает другие методы. Хотелось бы более изящного решения. В Юнити такое реализовано через Reflection (OnUpdate и т.п.), но мне кажется это не очень изящным.
Допустим, у нас есть такой EventManager:
class EventManager {
List<IListener> listeners = new List<IListener>();
public void Subscribe (IListener listener) {
listeners.Add( listener );
}
public void Publish (Event e) {
foreach (IListener listener in listeners) {
listener.OnEvent( e );
}
}
}
class Event {
public virtual string GetTitle () {
return "Title:Event";
}
}
interface IListener {
void OnEvent (Event e);
}
И много-много (на каждый чих) потенциальных событий. Скажем, несколько сотен:
class BuildEvent : Event {
public override string GetTitle () {
return "Title:BuildEvent";
}
}
class MoveEvent : Event {
public override string GetTitle () {
return "Title:MoveEvent";
}
}
class AttackEvent : Event {
public override string GetTitle () {
return "Title:AttackEvent";
}
}
class Program {
static void Main() {
Console.WriteLine("Hello, World!");
EventManager manager = new EventManager();
// Хендлеров может быть много и разным хендлерам нужны разные события
// Скажем, меню построек не реагирует на базовые действия юнитов
// А модулю статистики не важны факты об окончании ремонта
manager.Subscribe( new GameHandler() );
manager.Subscribe( new MenuHandler() );
manager.Subscribe( new CostHandler() );
manager.Subscribe( new LogHandler() );
// ну и тут эти события постоянно запускаются, допустим, это длительная сессия игры
manager.Publish( new BuildEvent() );
manager.Publish( new MoveEvent() );
manager.Publish( new BuildEvent() );
manager.Publish( new BuildEvent() );
manager.Publish( new AttackEvent() );
}
}
Так вот, как бы написать эту либу, чтобы можно было доподписывать нужные события? В идеале было бы, например, если это будет реализовано через method override
class GameHandler : IListener {
// Все события, которые зашли сюда - игнорируются
public void OnEvent (Event e) {}
// Необходимые события переопределяю отдельными методами через аргумент функции
public void OnEvent (MoveEvent e) {
Console.WriteLine( "Foo.OnMoveEvent: " + e.GetTitle() );
}
public void OnEvent (BuildEvent e) {
Console.WriteLine( "Foo.OnBuildEvent: " + e.GetTitle() );
}
}
Естественно, в подобной реализации идея не сработает. Такое, конечно, можно сделать свичем в OnEvent (Event e), как в первом блоке кода, но не хотелось бы писать глупый код и дублировать функциональность языка. Допускаю, что реализовывается через рефлексию, но хотелось бы ее избежать. Какие практики обычно используются в Java и C#?