我正在設計一個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