2017-02-11 82 views
3

我有一種方法,它由一些邏輯+底層系統調用組成。現在需要實現另一種包含完全相似的邏輯但僅包含底層系統調用更改的方法。消除類似函數定義的重複代碼

我試圖想出一些方法來重用通用代碼,並實現另一種方法,可能需要一個可調用的調用底層系統調用,但由於readrecv的調用是不同的,所以一直沒有成功。

很高興找到一個相同的優雅的解決方案。該方法看起來像 -


第一個功能

std::string Socket::read(const int bufSize) const 
{ 
    auto buffer = std::make_unique<char[]>(bufSize + 1); 
    auto recvd = 0, count = 0; 

    std::string str; 
    str.reserve(bufSize); 

    do { 

     // ONLY THIS PART IS DIFFERENT 
     recvd = ::read(sockfd, buffer.get() + count, bufSize - count); 
     // ONLY THIS PART IS DIFFERENT 

     count += recvd; 
     if (count == bufSize) { 
      str.append(buffer.get()); 
      str.reserve(str.length() + bufSize); 
      std::memset(buffer.get(), 0, bufSize); 
      count = 0; 
     } 
    } while (recvd > 0); 

    str.append(buffer.get(), count); 

    if (recvd == -1) { 
     // TODO: Check for recvd == EAGAIN or EWOULDBLOCK and 
     // don't throw exception in that case. 
     throw std::runtime_error("Error occurred while writing message"); 
    } 

    return str; 
} 

二功能

std::string Socket::recv(const int bufSize, SF::recv flags) const 
{ 
    auto buffer = std::make_unique<char[]>(bufSize + 1); 
    auto recvd = 0, count = 0; 

    std::string str; 
    str.reserve(bufSize); 

    do { 

     // ONLY THIS PART IS DIFFERENT 
     const auto f = static_cast<int>(flags); 
     recvd = ::recv(sockfd, buffer.get() + count, bufSize - count, f); 
     // ONLY THIS PART IS DIFFERENT 

     count += recvd; 
     if (count == bufSize) { 
      str.append(buffer.get()); 
      str.reserve(str.length() + bufSize); 
      std::memset(buffer.get(), 0, bufSize); 
      count = 0; 
     } 
    } while (recvd > 0); 

    str.append(buffer.get(), count); 

    if (recvd == -1) { 
     // TODO: Check for recvd == EAGAIN or EWOULDBLOCK and 
     // don't throw exception in that case. 
     throw std::runtime_error("Error occurred while writing message"); 
    } 

    return str; 
} 
+0

你能解釋一下代碼應該做什麼嗎?我明白了基本要點,但我認爲可能更簡單和更短的方法來實現兩者。 – tambre

+0

雖然我應該提到,簡單的方法是將功能邏輯簡單地分成不同的功能。沒有什麼驚天動地的。 – tambre

+0

@tambre從'套接字讀取並返回一個'std :: string'。 –

回答

2

在C++ 14,你可以這樣來做。這是一個更靈活的解決方案,雖然這不是爲滿足您的確切需要而設計的。結果,它可能變得不那麼富有表現力。

#include <utility> 

namespace detail { 

template <class Fn, class... Args> 
auto DuplicatedCode(Fn &&fn, Args&&... args) { 
    // some code 

    // auto result = 
    std::forward<Fn>(fn)(std::forward<Args>(args)...); 

    // more code 

    // return 
} 

} 

void foo() { 
    detail::DuplicatedCode([](){return 0;}); 
} 

void bar() { 
    detail::DuplicatedCode([](){return 1;}); 
} 

可以在foo和bar聲明一些局部變量和DucplicatedCode將它們轉發給fn或者你可以簡單地捕捉到這些變量。

+0

這是非常好的方法恕我直言,它也是完美轉發的例子,對吧?您是否介意檢查 - http://ideone.com/WNm35N,如果這是您的解決方案的使用目的。 –

+0

是的,確切地說。 Lambda表達式在這裏沒有必要,你明白了這一點,你會明白:)。你也可以根據需要修改fn的調用(在DuplicatedCode等中傳遞一些局部變量)。 – felix

3

當我要比較你的std::string Socket::read(const int bufSize) const和版本

enter image description here 唯一的區別是

const auto f = static_cast<int>(flags); 

recvd = ::recv(sockfd, buffer.get() + count, bufSize - count, f); 

因此,你的第一個版本可以進行重構,以使用一組特定的flags的第二版的調用。

或者你可以爲flags默認值像

std::string Socket::recv(const int bufSize, SF::recv flags = DefaultFlags) const 
1

最簡單的方法是總結的方法和傳遞一個無效標誌,如果讀消息稱爲:

if(flags==INVALID) 
     recvd = ::read(sockfd, buffer.get() + count, bufSize - count); 
    else 
     recvd = ::recv(sockfd, buffer.get() + count, bufSize - count, f); 

但是,這將違反Single Responsibility Principle,因爲該方法現在兩項職責和兩個原因改變。

更好的解決方案將是提取兩種方法的公共部分。

read() { 
commonMethod1(); 
::read(); 
commonMethod2(); 
} 
write() { 
commonMethod1(); 
::read(); 
commonMethod2(); 
} 

如何,您的問題可能是基於不同的意見,但這是我的。;-)

1

一種簡單的方法是將Socket

class Socket 
{ 
    // everything else you already have 

    private: 

     std::string recv_helper(int bufSize, const SF::recv *flags = nullptr) const; 
       // note the second argument is a pointer 
};  

中添加一個私有的輔助功能,並實現它作爲

std::string Socket::recv_helper(int bufSize, const SF::recv *flags) const 
{ 
    // All the code preceding your first // ONLY THIS PART IS DIFFERENT 

    if (flags) 
    { 
     recvd = ::recv(sockfd, buffer.get() + count, bufSize - count, 
         static_cast<int>(*flags)); 
    } 
    else 
    { 
     recvd = ::read(sockfd, buffer.get() + count, bufSize - count); 
    } 

     // All the code following your second // ONLY THIS PART IS DIFFERENT  
} 

然後,所有你需要做的是重新實現你的兩個功能打電話給幫手。

std::string Socket::read(int bufSize) const 
{ 
    return recv_helper(bufSize); 
} 

std::string Socket::recv(int bufSize, SF::recv flags) const 
{ 
    return recv_helper(bufSize, &flags); 
} 

請注意,我也從通過值傳遞的參數中刪除了多餘的const限定符。