[英]Class hierarchy design, avoiding downcasts from base to derived class
我正在用C ++设计一个DNS解析库。 DNS数据包具有一组标准字段,后跟资源记录列表,该列表还具有一组标准字段,后跟一个RData字段。 根据类型字段解析RData字段。 现在,我为DNSRData指定层次结构,以处理各种类型。 代码看起来像这样:
class DNSRData {
virtual void ToString() = 0;
virtual void Parse() = 0;
}
class DNSRData_A : public DNSRData {
void ToString();
void Parse();
uint32_t GetIP();
}
class DNSRData_CNAME : public DNSRData {
void ToString();
void Parse();
const char* GetAlias();
}
class DNSResourceRecord {
/* Standard Fields
..... */
int type_; // Specifies the format for rdata_
DNSRData *rdata_;
}
class DNSPacket {
/* Standard Fields
....*/
vector<DNSResourceRecord *> rr_list_;
}
现在这是我的问题,每个DNSRData记录可能有不同的字段。 我不想为Base类中的所有字段添加访问器,因为它们存在于某些派生类中而不存在于其他派生类中,例如IP地址仅存在于DNSRData_A中而不存在于任何其他类别中。
因此,当我想对DNSRData执行任何操作时,我查找类型并执行从DNSRData *到DNSRData_A *的向下转换。
DNSRData *rdata = packet->GetResourceRecord().front(); //not really necessary for this example
if(resource_record.type == RR_CNAME) {
DNSRData_CNAME *cname = (DNSRData_CNAME*)rdata;
}
这可能会导致以后出现大量问题,而且随着我们添加更多类型,它很快就变成了一个不圣洁的混乱。 有关如何在不向Base类添加所有访问器的情况下解决此问题的任何想法?
编辑 :
更多上下文,这是高性能DNS跟踪解析库的一部分。 当我们看到线路上的数据包时,很多操作都已完成。 那么,什么是混淆设计的操作,让我们说我们得到一个DNSPacket并且现在我们解析它我们想要决定如何根据类型进一步处理它。
if(type == RR_CNAME) {
DNSRData_CNAME *cname = dynamic_cast<DNSRData_CNAME*>(&rdata);
char *alias = cname->GetAlias();
}else if (type = RR_A) {
DNSRData_A *a = dynamic_cast<DNSRData_A*>(&rdata);
uint32_t ip = a->GetIP();
}
如您所见,从基本类型RData到更具体的RData类型涉及到一个向下转换。 我想避免这种垂头丧气,并使用一种设计模式来解决这个问题。
如果我理解正确的话,我认为访客模式就是你要找的
访客模式 。
class GetInfoVisitor
{
void visit(DNSRData_A* a)
{
uint32_t ip = a->GetIP();
}
void visit(DNSRData_CNAME * cname)
{
char *alias = cname->GetAlias();
}
}
class DNSRData
{
void action(Visitor& visitor)
{
visitor.visit(this);
}
}
int main()
{
...
GetInfoVisitor getInfoVisitor;
DNSRData *rdata = packet->GetResourceRecord().front();
rdata->action(getInfoVisitor);
}
首先,您可能需要考虑dynamic_cast,而不是您在示例中使用的c样式转换。 这将允许您检查演员表是否成功,这可以避免潜在的严重错误。
其次,我认为可能需要更多背景来回答你的问题。 几乎无一例外,良好地使用设计模式可以让您避免这种情况开始。 鉴于手头的信息,我建议甚至可以在父类中创建一个名为operations的抽象虚函数,然后可以重写该函数来实现感兴趣的特殊逻辑。 这将允许您在任何人覆盖基类时考虑问题,因此代码更易于维护,并且由于避免查找类型而节省时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.