1

私は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タイプへのダウンキャストが関係しています。このダウンキャストを避け、おそらくデザインパターンを使用してこの問題を解決したいと思います。

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

まず、例で使用したcスタイルのキャストではなく、dynamic_castを検討することをお勧めします。これにより、キャストが成功したかどうかを確認できるため、重大なエラーが発生する可能性を回避できます。

第二に、私はあなたの質問に答えるためにもっと多くの文脈が必要かもしれないと思います。ほとんどの場合、デザインパターンを適切に使用することで、最初からこの状況を回避できます。ただし、手元にある情報を考えると、親クラスでoperateという抽象的な仮想関数を作成し、それをオーバーライドして目的の特別なロジックを実装することをお勧めします。これにより、誰かが基本クラスをオーバーライドするたびに問題を検討できるため、コードの保守が容易になり、型の検索を回避できるため時間を節約できます。

于 2012-06-24T04:07:17.623 に答える