2014-11-01 42 views
2

我想在C++中設計一個使用FTP,SFTP實現文件傳輸的包裝類。設計一個包裝多種功能的優秀C++包裝類

我有一個基類FileTransfer(使用curl),它是由派生類FTP繼承的。我需要支持SFTP,所以我實現了另一個派生類SFTP,它也繼承自FileTransfer

我沿着以下幾行製作了一個包裝類代碼。但是,這看起來不是很好的設計。我對OOP比較陌生,儘管過去我曾在C上工作過。

class Wrapper { 
 
    public: 
 
    Wrapper(int m_protocol){ 
 
    protocol = m_protocol; 
 
    if (protocol) 
 
     pftp = new FTP(); 
 
    else 
 
     psftp = new SFTP(); 
 
    } 
 
    
 
    ~Wrapper() { 
 
    if (protocol) 
 
     delete pftp; 
 
    else 
 
     delete psftp; 
 
    } 
 
    //Function supported by both ftp/sftp 
 
    void do_something(){ 
 
    if (protocol) 
 
     pftp->do_something(); 
 
    else 
 
     psftp->do_something(); 
 
    } 
 
    
 
    //FTP specific function 
 
    void use_passive(){ 
 
    assert(protocol); 
 
    pftp->use_passive(); 
 
    } 
 
    
 
    //SFTP specific function 
 
    void ssh_key(){ 
 
    assert(!protocol); 
 
    psftp->ssh_key(); 
 
    } 
 
    
 
    private: 
 
    int protocol; 
 
    FTP *pftp; 
 
    SFTP *psftp; 
 
};

我怎樣才能改善這種設計?如何避免每個函數中的if (protocol)檢查並提高代碼質量?我應該使用void指針作爲psftp和'pftp`嗎?

編輯:我使用的包裝,因爲在項目中的很多地方,現有的FTP對象正在使用,如果我使用單獨的類爲SFTP(沒有包裝),我將不得不添加一個if檢查每次也支持SFTP。我不想將詳細信息(FTP/SFTP)公開給調用者。

+1

你爲什麼使用包裝? – Vincent 2014-11-01 15:47:03

+2

你需要包裝嗎?似乎大多數情況下,您只需要一個'FileTransfer *',它可以是'FTP *'或'SFTP *'。絕對不是*兩個*指針,絕對不是'void *'。 – Barry 2014-11-01 15:47:55

+0

我正在使用一個包裝,因爲在項目中的很多地方,現有的FTP對象正在使用,如果我使用SFTP(沒有包裝)單獨的類,我將不得不添加一個'if'檢查每次也支持SFTP。我想讓呼叫者不知道它是FTP還是SFTP。 – 2014-11-01 15:51:49

回答

2

只需使用基類指針就可以輕鬆完成此處的所有操作。

FileTransfer* ft; 
std::unique_ptr<FileTransfer> ft; // C++11 

製作一個:

// should this really be an int? 
FileTransfer* factory(int protocol) { 
    if (protocol) 
     return new FTP; 
    else 
     return new SFTP; 
} 

// in C++11 this should be 
std::unique_ptr<FileTransfer> factory(int protocol); 

做一些:

ft->do_something(); 

做一些具體的事情,以一種或另一種:

// this will die if ft is an SFTP 
dynamic_cast<FTP*>(ft)->use_passive(); 

// but you could check it 
if (FTP* ftp = dynamic_cast<FTP*>(ft)) { 
    ftp->use_passive(); 
} 

// or perhaps even better, make a default virtual that does nothing 
virtual void FileTransfer::use_passive() { } 

void FTP::use_passive() override { // whatever } 

ft->use_passive(); 

刪除:

// make sure FileTransfer::~FileTransfer() is virtual!! 
delete ft; 
+0

謝謝。在'FileTransfer'中創建虛擬成員函數更有意義。使用dynamic_cast,調用者將不得不重複創建指向'FTP' /'SFTP'的指針。 – 2014-11-01 21:06:30

+0

讓我們假設,不是返回'void',而是use_passive'返回一個int('int(){}'),這會給出錯誤FileTransfer :: use_passive必須返回一個值。我不能使這個純虛函數,因爲這將使類Abstract,我將不得不在SFTP類中實現'use_passive'。可以做些什麼來防止這種情況發生? – 2014-11-02 10:18:13

2

所有你需要的是polymorphism使用指針FileTransfer,使得do_something()~FileTransfer()析構虛函數(即你invoque的基礎對象指針的功能,以及對象將調用正確的函數依賴於它真正的類)。

剩下的問題只是關於基於協議的對象構造。正確的術語不是「包裝」,而是「factory」(設計模式)。這可以通過FileTransfer的靜態成員函數來實現。