1

我正在用 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 类型的向下转换。我想避免这种沮丧,并使用一种设计模式来解决这个问题。

4

2 回答 2

4

如果我理解正确,我认为访问者模式就是您正在寻找的

访客模式

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);
}
于 2012-06-24T04:41:56.540 回答
0

首先,您可能需要考虑 dynamic_cast,而不是您在示例中使用的 c 样式转换。这将允许您检查转换是否成功,这可以避免潜在的严重错误。

其次,我认为可能需要更多背景信息来回答您的问题。几乎总是,良好地使用设计模式可以让您从一开始就避免这种情况。不过,鉴于手头的信息,我建议甚至在父类中创建一个称为操作的抽象虚函数,然后可以重写该函数以实现感兴趣的特殊逻辑。这将允许您在有人覆盖基类的任何时候考虑问题,因此代码更易于维护,并且由于避免查找类型而可以节省时间。

于 2012-06-24T04:07:17.623 回答