我正在设计一个C++中的DNS解析库。 DNS数据包具有一组标准字段,后跟资源记录列表,其中又有一组标准字段,后跟RData字段。 RData字段根据类型字段进行分析。现在,我为DNSRData指定一个层次结构来处理各种类型。代码看起来像这样:类层次设计,避免从基类到派生类的downcast
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中,不存在于其他任何IP地址中。
因此,当我想对DNSRData执行任何操作时,我查找类型并从DNSRData *向DNSRData_A *执行downcast。
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类型都存在一个倒退。我想避免这种沮丧,并使用可能的设计模式来解决这个问题。
jojo钉了它,我很确定访客正是你要找的。避免使用'virtual void ToString()'和'Parse()'成员函数,用'ToStringVisitor'和'ParseVisitor'类替换它们。 – mergeconflict
当某些派生类中存在某些方法而不是其他方法时,访问者将如何工作。例如:GetIP只有DNSRData_A和GetAlias只在DNSRData_CNAME中,都来自基本DNSRData – creatiwit
@shrin我添加了一些代码,我希望它可以帮助 – jojo