根据数据包类型改变行为,避免 switch 语句

Changing behaviour depending on packet type, avoiding switch statements

我正在编写一个主要通过数据包进行通信的服务器-客户端架构程序。我很难想出一个更 eloquent 的方法来实现这个目标。

这是我目前拥有的东西:

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

不过,我 运行 遇到了一些障碍。显然我不能在 TCP 枚举的值上重载 sendPacket。我可以让每个枚举器类型都有自己的结构,但是我失去了将数据包快速转换为 int 的能力,这对于接收方了解它是什么类型的数据包至关重要。这可以通过添加一个虚拟 getId() 函数来解决,但这只是一种单向转换(Packet 到 int),而我还需要以某种方式从 int 转换为 Packet。

您可以创建一个 std::functions 的向量并使用 _type 作为索引。每个索引处都是处理该特定类型数据包的函数。那么您的代码可能如下所示:

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

然后你可以用这个代替开关:

handlers[code](p);