2017-02-11 7 views
3

私はいくつかのロジック+基本システムコールで構成されたメソッドを持っています。まったく同じロジックを含み、基盤となるシステムコールの変更だけを含むもう1つの方法を実装する必要があります。は、同じような関数定義の重複コードを排除します。

共通のコードを再利用する方法を考えています。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は ' socket'から読み込み、' std :: string'を返します。 –

答えて

2

のデフォルト値を提供することができます。これはあなたの正確なニーズに合わせて設計されていませんが、より柔軟なソリューションです。その結果、表現力が低下することがあります。

#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にいくつかのローカル変数を宣言することができ、かつDucplicatedCodefnにそれらを転送するか、あなたは、単にこれらの変数をキャプチャすることができます。

+0

これは非常に良い方法ですimho、それも完全な転送のための例ですか?これがあなたのソリューションの意図された使用であれば、あなたはhttp://ideone.com/WNm35Nをチェックしてください。 –

+0

はい、正確です。ラムダ式はここでは必要ありません、あなたはこの点を得る、あなたは全体のアイデアを得る:)。必要に応じてfnの呼び出しを変更することもできます(DuplicatedCodeなどのローカル変数を渡します)。 – felix

3

私はstd::string Socket::read(const int bufSize) constとのあなたのバージョンを比較するつもりです

enter image description here 唯一の違いは、このようにあなたの第一バージョンがflagsの特定のセットを使用して第二版の呼び出しにリファクタリングすることができ

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

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

です。

それとも、あなたは、このようにそれを行うことができますC++ 14では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); 

しかし、この方法は現在2人の責任と二つの理由を持っているので、これは、Single Responsibility Principleに違反することになります変更する。

もっと良い解決策は、両方の方法の共通部分を抽出することです。

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

あなたの質問はおそらく異なる意見に基づいていますが、これは私のものです。;-)

1

1つの簡単な方法は、

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 
};  

Socketクラス内のプライベートヘルパー関数を追加し、

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修飾子を値渡しの引数から削除しました。

関連する問題