为什么我们,包括我自己,总是把这么简单的问题搞得这么复杂?
也许我不在这儿了。但我不得不怀疑:这真的是满足您需求的最佳设计吗?
总的来说,仅函数继承可以通过函数/方法指针,或聚合/委托以及数据对象的传递来更好地实现,而不是通过多态。
多态是一个非常强大和有用的工具。但这只是我们可用的众多工具之一。
看起来 Packet 的每个子类都需要自己的编组和解组代码。也许继承了 Packet 的 Marshalling/Unmarshalling 代码?也许延长它?一切都在 handle() 和其他任何需要的基础之上。
代码太多了。
虽然更加笨拙,但将 Packet 的数据实现为 Packet 类的结构/联合属性可能会更短、更快。
然后,编组和解组将集中化。
根据您的架构,它可以像 write(&data) 一样简单。假设您的客户端/服务器系统之间没有大/小端问题,也没有填充问题。 (例如 sizeof(data) 在两个系统上都是相同的。)
Write(&data)/read(&data) 是一种容易出错的技术。但这通常是编写初稿的一种非常快速的方法。稍后,如果时间允许,您可以将其替换为基于每个属性类型的编组/解组代码。
另外:我已经开始将作为结构发送/接收的数据存储起来。您可以使用 operator=() 按位复制结构,这有时非常有用!虽然在这种情况下可能没有那么多。
最终,您将在该 subclass-id 类型的某处有一个 switch 语句。工厂技术(它本身就非常强大和有用)会为您完成此切换,查找必要的 clone() 或 copy() 方法/对象。
或者你可以在 Packet 中自己做。您可以使用如下简单的东西:
(getHandlerPointer(id))(这个)
除了快速的开发时间之外,这种方法的另一个优点(函数指针)是您不需要不断地为每个数据包分配和删除一个新对象。您可以一遍又一遍地重复使用单个数据包对象。或者,如果您想将它们排队,则为数据包向量。 (请注意,我会在再次调用 read() 之前清除 Packet 对象!为了安全起见......)
根据您游戏的网络流量密度,分配/解除分配可能会变得昂贵。话又说回来,过早的优化是万恶之源。而且你总是可以滚动你自己的新/删除操作符。 (还有更多的编码开销......)
您失去的(使用函数指针)是每种数据包类型的干净隔离。特别是能够在不更改现有代码/文件的情况下添加新的数据包类型。
示例代码:
class Packet
{
public:
enum PACKET_TYPES
{
STATE_PACKET = 0,
PAUSE_REQUEST_PACKET,
MAXIMUM_PACKET_TYPES,
FIRST_PACKET_TYPE = STATE_PACKET
};
typedef bool ( * HandlerType ) ( const Packet & );
protected:
/* Note: Initialize handlers to NULL when declared! */
static HandlerType handlers [ MAXIMUM_PACKET_TYPES ];
static HandlerType getHandler( int thePacketType )
{ // My own assert macro...
UASSERT( thePacketType, >=, FIRST_PACKET_TYPE );
UASSERT( thePacketType, <, MAXIMUM_PACKET_TYPES );
UASSERT( handlers [ thePacketType ], !=, HandlerType(NULL) );
return handlers [ thePacketType ];
}
protected:
struct Data
{
// Common data to all packets.
int number;
int type;
union
{
struct
{
int foo;
} statePacket;
struct
{
int bar;
} pauseRequestPacket;
} u;
} data;
public:
//...
bool readFromSocket() { /*read(&data); */ } // Unmarshal
bool writeToSocket() { /*write(&data);*/ } // Marshal
bool handle() { return ( getHandler( data.type ) ) ( * this ); }
}; /* class Packet */
PS:你可能会用谷歌搜索并下载 cdecl/c++decl。它们是非常有用的程序。尤其是在玩弄函数指针时。
例如:
c++decl> declare foo as function(int) returning pointer to function returning void
void (*foo(int ))()
c++decl> explain void (* getHandler( int ))( const int & );
declare getHandler as function (int) returning pointer to function (reference to const int) returning void