我正在用 C++ 设计一个 DNS 解析库。DNS 数据包具有一组标准字段,后跟一个资源记录列表,该列表再次具有一组标准字段,后跟一个 RData 字段。RData 字段是根据 type 字段解析的。现在,我为 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 记录可能有不同的字段。我不想为基类中的所有字段添加访问器,因为它们存在于某些派生类中,而不存在于其他类中,例如 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;
}
这可能会在以后导致大量问题,并且随着我们添加更多类型,它很快就会变得一团糟。关于如何在不将所有访问器添加到基类的情况下解决此问题的任何想法?
编辑:
更多上下文,这是高性能 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 类型的向下转换。我想避免这种沮丧,并使用一种设计模式来解决这个问题。