我正在开发网络程序并使用C ++设计Linux服务器。设计基本结构非常简单。我有一个数据包定义,其头部具有固定的大小。
typedef enum{
PACKET_LOGIN_REQ = 1,
PACKET_LOGIN_RES,
PACKET_STORE_REQ,
PACKET_STORE_RES
}PACKET_TYPES;
typedef struct {
PACKET_TYPES type;
short bodySize,
long long deviceId
}HEADER;
.
.
/*more definitions here*/
typedef struct{
HEADER head;
union BODY{
LOGIN_REQ loginReq;
LOGIN_RES loginRes;
.
.
more types
}
}
每当我添加更多数据包类型时,我都必须修改switch语句以添加更多案例来处理新添加的数据包。
我正在使用union类型,所以我不必更改整个数据包结构。相反,我可以将新添加的数据包类型添加到联合结构中。
但是,当我尝试使用switch
语句解析原始数据以放入数据包时,我每次都必须添加每个switch
语句。
我认为这不是一个好的设计模式,我想知道如何以更灵活的方式设计结构。
有没有更好的方法来处理这个问题(更好的设计模式)?相关的教程或参考怎么样?
答案 0 :(得分:7)
您应该使用类而不是switch
使用多态调用。
类似的东西(伪编码):
class Packet{
public:
Packet();
virtual ~Packet();
virtual HandleMe()=0;
protected:
// fields
}
PacketTypeOne: public Packet{
public:
virtual HandleMe(); // implementation for type 1
}
PacketType2: public Packet{
public:
virtual HandleMe(); // implementation for type 2
}
PacketTypeX: public Packet{
public:
virtual HandleMe(); // implementation for type X
}
以及获取数据包的地方:
...
Packet* newPacket = PacketFactory::CreateNewPacket(packetTypeX); // factory will create
// the right instance.
...
// now handle it:
newPacket->HandleMe();
...
完成。
答案 1 :(得分:3)
由于你的代码是C风格而不是C ++风格代码,我会给你C答案。
使用函数指针。类似的东西:
typedef int (*ParseFunc)(const char *, len, struct MyStruct);
typedef struct PacketParser_
{
PACKETType type;
ParseFunc parseFunc;
} PacketParser;
const PacketParser[] parser =
{
{ PACKET_LOGIN_REQ, LoginReqParser }
{ PACKET_LOGIN_RES, LoginResParser }
.
.
.
}
然后遍历所有数据包类型并调用相应的函数。每当您获得新的数据包类型时,只需在PacketParser
函数中添加另一行。
如果您使用的是C ++,最好使用多态。
答案 2 :(得分:1)
在大多数情况下,您应该避免使用union
。这是其中一种情况: - )
如上所述,答案是使用多态性。将switch语句转换为多态的规范方法是使用Visitor design pattern。
虽然正常的多态性,使用virtual
方法可以帮助你,但是存在问题。 virtual
方法可以根据单个对象(Packet
)为您分配正确的方法。但是,您还要依赖采取的行动。例如,如果您有许多switch
个语句而不是一个,那么Visitor
模式将更可取。
答案 3 :(得分:0)
你可能想......
基本上,你会找到一个好的超类,并为每个类型代码创建一个不同的子类。
您还想购买 “重构:改进现有代码设计”的副本。 ,Fowler,Martin(1999)/ Addison Wesley。 。