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