2017-02-11 12 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는' socket'에서 읽고'std :: string'을 반환합니다. –

답변

2

같은 flags에 대한 기본값을 제공 할 수있다. 이 방법은 사용자의 필요에 맞게 설계되지는 않았지만보다 유연한 솔루션입니다. 결과적으로 표현력이 떨어지게됩니다.

#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는 바의 일부 지역 변수를 선언 할 수 있으며, DucplicatedCodefn로 전달되거나 단순히 그 변수를 캡처 할 수 있습니다. 이 방법은 이제 두 개의 책임과 두 가지 이유가 있기 때문에이는 Single Responsibility Principle을 위반하는 것,

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

을하지만 :

+0

이것은 아주 좋은 방법입니다. imho, 완벽한 전달을위한 예가 맞습니까? 귀하의 솔루션을 의도적으로 사용하는 것이라면 - http://ideone.com/WNm35N을 확인해주십시오. –

+0

네, 그렇습니다. 람다 표현식은 여기에서 필요하지 않습니다, 당신은이 점을 얻습니다, 당신은 전체 아이디어를 얻습니다 :). 필요한 경우 fn에 대한 호출을 수정할 수도 있습니다 (DuplicatedCode의 일부 로컬 변수 전달 등). – felix

3

내가 std::string Socket::read(const int bufSize) const과당신의 버전을 비교하는거야

enter image description here 유일한 차이점은 따라서 귀하의 첫 번째 버전은 flags의 특정 세트를 사용하여 2 버전의 호출에 리팩토링 할 수

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

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

입니다.

또는 당신은 C++ (14) 당신이이 방법을 수행 할 수 있습니다에서

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

가장 쉬운 해결책은 읽기 메시지가 불려 갔을 경우, 방법을 요약하고 유효하지 않은 플래그를 전달하는 것입니다 바꾸다.

더 나은 해결책은 두 가지 방법의 공통 부분을 추출하는 것입니다.

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

언제 까지나 귀하의 질문은 다른 의견을 토대로 한 것이지만, 본인은 제 것입니다.;-)

1

한 가지 간단한 방법은 다음 당신이해야 할 모든 당신의 두 가지 기능을 구현할됩니다

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  
} 

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

내에서 개인 도우미 기능을 추가하고 구현하는 것입니다 도우미에게 전화하기. 나는 또한 값에 의해 전달 된 인수의 중복 const 한정자를 제거한

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

참고.