添加参数或添加功能?

时间:2014-11-10 08:58:42

标签: c++ parameters

编码时我总是遇到这样的问题。

有一个名为" INetworkReader"的界面,如下所示:

struct INetworkReader
{
    virtual void readFile(const std::string& url) = 0;
    ...
};

现在,我想扩展readFile()函数,readFile()函数需要设置超时或其他东西以实现更多控件,所以现在我有两个解决方案。

解决方案1(添加默认参数):

struct INetworkReader
{
    virtual void readFile(const std::string& url, int timeout = 0) = 0;
    ...
};

解决方案2(添加另一个功能):

struct INetworkReader
{
    virtual void readFile(const std::string& url) = 0;
    virtual void readFileTimeout(const std::string& url,int timeout) = 0;
    ...
};

我更喜欢解决方案1,因为它的参数清楚地描述了它的动作,我认为唯一的缺点就是增加了参数的数量。

那么,如你所见,哪个看起来更好?为什么呢?


我发现了另一个可能更复杂的案例,请查看以下代码。

struct IComputer
{
    virtual bool addMouse(/* in */const std::string& mouseID, /*out*/ IMouse** ppMouse ) = 0;
}

现在想要添加一个参数来判断它是否添加到USB端口,这些仍然有两个解决方案。

解决方案1(添加默认参数):

struct IComputer
{
    virtual bool addMouse(/* in */const std::string& mouseID, /*out*/ IMouse** ppMouse, /* in */ bool USBPort = true ) = 0;
}

解决方案2(添加另一个功能):

struct IComputer
{
    virtual bool addMouse(/* in */const std::string& mouseID, /*out*/ IMouse** ppMouse ) = 0;
    virtual bool addMouseNotUSB(/* in */const std::string& mouseID, /*out*/ IMouse** ppMouse ) = 0;
}

这次我更喜欢第二个解决方案,因为第一个解决方案已经打破了输入输出参数的序列。

那么,两个案例,四个解决方案,哪一个更好?为什么呢?

3 个答案:

答案 0 :(得分:1)

IMO我更喜欢解决方案2(只要它需要一个超时参数)。如果您是第一次面对代码,则可以快速了解表达式readFileTimeout(url, 1000)中的“1000”,而不是readFile(url, 1000)。在第二个表达式中,人们可以认为代码正在读取1000个字节,例如。

在第二种情况下,我也更喜欢使用不同的函数名,但由于我们传递了一个布尔值,我会使用函数名来从中推导出布尔值:

addMouse(const std::string& mouseID, IMouse** ppMouse) //For non-USB mice
addUSBMouse(const std::string& mouseID, IMouse** ppMouse) //For USB mice

是否使用反逻辑(即创建addNonUSBMouse而不是addUSBMouse)的决定是任意的,取决于您的代码可能会运行的情况。如果在大多数情况下鼠标不是USB,请使用我的建议。否则使用逆逻辑版本。

我的引理是:尝试以不必阅读原型的方式命名函数。

答案 1 :(得分:1)

另一个选择是使用类型强制在调用代码中表达:

struct INetworkReader
{
    virtual void readFile(const std::string& url, Timeout timeout = Timeout::Infinite) = 0;
    ...
};

调用代码可能是:

p->readFile(url, Timeout{200, Timeout::ms});

表示Timeout为0有点模棱两可:它可能意味着对数据进行非阻塞检查,或者可能无限期阻止,因此值为InfiniteNever更清楚。

使用C ++ 14,您可以从std::chrono::duration创建一个明确的Timeout构造函数,例如200ms

对于鼠标示例:

    enum Connection { USB, NonUSB };
    virtual std::pair<bool, IMouse*> addMouse(const std::string& mouseID,
                                              Connection connection = USB ) = 0;

请注意,对于输入/输出参数问题,我已经返回了所有输出而不是IMouse**?您可以返回tuplepair或自定义struct

答案 2 :(得分:0)

溶液1是优选的。对于包含两个参数的函数来说,它绝对可以。当参数太多时,只需考虑其他解决方案(例如构造函数的参数太多的Builder模式)。