我有一个由一些逻辑+底层系统调用组成的方法。现在,必须实现另一种方法,该方法包含完全相似的逻辑但只有底层系统调用更改。
我正在尝试某种方式来重用公共代码并实现另一种方法,该方法可能需要一个可调用来调用底层系统调用,但由于read
和{{ 1}}来电不同。
很高兴能找到一个优雅的解决方案。方法看起来像 -
第一个功能
recv
第二功能
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;
}
答案 0 :(得分:3)
当我要比较std::string Socket::read(const int bufSize) const
和std::string Socket::recv(const int bufSize, SF::recv flags) const
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 :(得分: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
,或者您可以简单地捕获这些变量。
答案 2 :(得分: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();
}
然而,你的问题可能基于不同的意见,但这个是我的。 ; - )
答案 3 :(得分:1)
一种简单的方法是在library(clpfd)
类
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);
}
限定符。