Изменение поведения в зависимости от типа пакета, избегая операторов switch - PullRequest
2 голосов
/ 14 мая 2019

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

Вот что у меня есть на данный момент:

namespace Packet {    
    enum class TCP {
        PLAYER_JOINED,
        PLAYER_QUIT,
        MESSAGE_SENT
    };
}

Наряду с этими функциями для преобразования типов в целочисленные коды и наоборот:

constexpr auto toInt(Packet::TCP _t) {
    return static_cast<std::underlying_type_t<Packet::TCP>>(_t);
}
constexpr Packet::TCP toTCPType(int _i) {
    return static_cast<Packet::TCP>(_i);
}

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

void sendPacket(Packet::TCP _type) {
    int code{Packet::toInt(_type);
    Packet p;
    p << code;

    switch (_type) {
        case Packet::TCP::PLAYER_JOINED:
            //do stuff and operate on p
            break;
        case Packet::TCP::PLAYER_QUIT:
            //do stuff and operate on p
            break;
        //etc.
    }
}

Я бы предпочел, чтобы это было что-то вроде этого:

void preparePacket(Packet::TCP _type) {

    //common behaviour that has to be done no matter the type 
    int code{Packet::toInt(_type);
    Packet p;
    p << code;

    sendPacket(_type, p);
}

Хотя я сталкиваюсь с несколькими препятствиями. Очевидно, я не могу перегрузить sendPacket значением перечисления TCP. Я мог бы заставить каждый перечислитель печатать свою собственную структуру, но затем я терял способность быстро преобразовывать Пакеты в int, что жизненно важно для получателя, чтобы знать, что это за пакет. Эту проблему можно решить, добавив виртуальную функцию getId (), но тогда это только одностороннее преобразование (Packet в int), тогда как мне также нужно каким-то образом преобразовать из int в Packet.

1 Ответ

2 голосов
/ 14 мая 2019

Вы можете создать вектор из std :: functions и использовать _type в качестве индекса.В каждом индексе будет функция, которая обрабатывает этот конкретный тип пакета.Тогда ваш код может выглядеть примерно так:

std::vector<std::function<void(Packet)>> handlers = { 
   player_joined_handler,
   player_quit_handler,
   message_sent_handler,
}

и тогда вместо переключателя вы можете получить это:

handlers[code](p);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...