Я хотел бы использовать асинхронный шаблон событий, чтобы отделить мою программу.Я также хотел бы, чтобы базовый класс событий не обращал внимания на реализации, чтобы иметь максимально широкую свободу передавать все, что мне нравится, к событию.Поэтому использование static_cast внутри коммутатора кажется мне простым и, возможно, безопасным решением:
enum class EventType
{
None,
EventA,
EventB
};
class BaseEvent
{
public:
BaseEvent(EventType t = EventType::None) : type(t) { }
virtual ~BaseEvent() {}
auto get_type() { return type; }
private:
EventType type;
// Oblivious and clean interface
};
class EventA : public BaseEvent
{
public:
EventA() : BaseEvent(EventType::EventA) { }
// ... whatever I like
};
class EventB : public BaseEvent
{
public:
EventB() : BaseEvent(EventType::EventB) { }
// ... whatever I like
};
void handle_event(BaseEvent* pe)
{
switch (pe->get_type())
{
case EventType::EventA:
{
EventA* original_a = static_cast<EventA*>(pe);
// In this case I know what is "pe" and what
// operations and data I can access and use.
break;
}
case EventType::EventB:
{
EventB* original_b = static_cast<EventB*>(pe);
//...
break;
}
}
}
Но я также знаю, что использование static_cast представляет некоторый риск, поскольку оно нарушает проверку типов.С моей идеалистической точки зрения это не кажется таким опасным в этом случае, даже для будущего обслуживания.Нужно только проверить, что строка
case EventType::EventA:
соответствует следующей строке
EventA* original_a = static_cast<EventA*>(pe);
Я знаю, что в теории это может показаться не проблемой, но практика действительно отличается,Может ли это решение работать для большого проекта?Есть ли более эффективные стратегии для реализации этого шаблона?
Я знаю, что мог бы использовать массив или вектор std :: variable в базовом классе, но это выглядит довольно ограниченно в отношении возможных реализаций производных событий.Я мог бы также использовать карту для хранения имен параметров и их значений, но она кажется довольно медленной, а память недружественной и также ограничивает возможные типы параметров.
В качестве альтернативы я мог бы также использовать dynamic_cast
, хотя он имеет своинакладные расходы, но, возможно, это окупает затраты, увеличивая удобство обслуживания.
РЕДАКТИРОВАТЬ
Чтобы быть кратким, я забыл упомянуть некоторые важные детали по этому вопросу:
- События должны быть помещены в контейнер полиморфно, поэтому я думаю, что CRTP это неосуществимо.
Контекст - это агентское моделирование в реальном времени (видеоигра), где у меня естьОсновной цикл итерации по событиям.События могут быть запущены где угодно в каждой итерации.Они будут обработаны определенными обработчиками в следующих итерациях.
std::queue<BaseEvent*> past_events;
int main()
{
while (true)
{
while (!past_events.empty())
{
handle_event(past_events.front());
//handle_event2(...)
//handle_event3(...)
//...
past_events.pop();
}
// New events are fired...
}
}