布尔作为方法论证是不可接受的吗?

Tho*_*hel 122 enumeration boolean coding-style

我的一位同事表示,布尔作为方法论据是不可接受的.它们应由枚举代替.起初我没有看到任何好处,但他给了我一个例子.

什么更容易理解?

file.writeData( data, true );
Run Code Online (Sandbox Code Playgroud)

要么

enum WriteMode {
  Append,
  Overwrite
};

file.writeData( data, Append );
Run Code Online (Sandbox Code Playgroud)

现在我明白了!;-)
这绝对是一个例子,枚举作为第二个参数使代码更具可读性.

那么,您对此主题有何看法?

ska*_*man 130

Boolean表示"是/否"选项.如果你想表示"是/否",那么使用布尔值,它应该是不言自明的.

但是,如果它是两个选项之间的选择,两者都不是明显是或否,那么枚举有时可以更具可读性.

  • 怎么样`setLightOn(bool)`. (16认同)
  • "turnLightOn(false)"表示"不开灯"?Confusiong. (13认同)
  • 虽然在这种情况下我可能更喜欢turnLightOn()和turnLightOff(),具体取决于具体情况. (10认同)
  • 迟到的评论,但@Jay Bazuzi:如果你的方法被称为turnLightOn,你传入false,你也可以根本不调用该方法,传入false表示不要打开灯.如果灯已经打开,它并不意味着将其关闭,这意味着不要打开它...如果你有一个方法'turnLight'一个带'On'和'Off'的枚举有意义,turnLight( On),turnLight(关闭).我同意skaffman,我宁愿两种不同的显式方法,turnLightOn()和turnLightOff().(顺便说一下:这个东西在Uncle Bobs的书"Clean Code"中有解释) (10认同)
  • 此外,方法名称必须清楚参数是或否,即void turnLightOn(bool)clealy设置为true或yes将使灯亮起. (3认同)

sim*_*mon 50

枚举还允许将来修改,您现在需要第三种选择(或更多).

  • @Rich:http://thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx (10认同)
  • 或者Win32的GetMessage():TRUE,FALSE或-1. (3认同)

Jer*_*que 32

使用最能模拟问题的那个.在您给出的示例中,枚举是更好的选择.但是,有时布尔值会更好.这对你更有意义:

lock.setIsLocked(True);
Run Code Online (Sandbox Code Playgroud)

要么

enum LockState { Locked, Unlocked };
lock.setLockState(Locked);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我可能会选择布尔选项,因为我认为它非常明确且毫不含糊,而且我很确定我的锁定不会超过两个状态.尽管如此,第二种选择是有效的,但不必要的复杂,恕我直言.

  • 这是一个公平的评论,但我认为这也说明了有很多方法来模拟给定问题.您应该根据具体情况使用最佳模型,并且还应该使用编程环境提供的最佳工具来适合您的模型. (3认同)
  • 在你的例子中,我宁愿有两种方法.lock.lock()lock.release()和lock.IsSet,但这一切都取决于对消费代码最有意义的东西. (2认同)

Tim*_*vis 13

我认为你自己几乎已经回答了这个问题,我认为最终的目的是让代码更具可读性,在这种情况下,枚举就是这样做的,IMO总是最好看看最终目标而不是一揽子规则,或许更多地考虑它作为指导,即代码通常在代码中比通用bool,int等更易读,但规则总会有例外.


Tho*_*n79 13

还记得Adlai Stevenson在古巴导弹危机期间向联合国大使佐林提出的问题吗?

"你现在正处于世界舆论的审判室,你可以回答 是或否.你否认[导弹]存在,我想知道我是否理解正确......我准备等待如果这是你的决定,直到地狱冻结为止我的回答."

如果您的方法中的标志具有这样的性质,您可以将其固定为二元决策,并且该决定永远不会变成三向或n向决策,那么请选择布尔值.适应症:你的旗帜叫做isXXX.

如果是模式切换,请不要将其设为布尔值.首先编写方法时,总会有一种模式比您想象的还要.

一个多模式的困境就像困扰Unix一样,文件或目录今天可能拥有的权限模式会导致模式的奇怪双重含义,具体取决于文件类型,所有权等.


Sam*_*tte 13

我遇到的两个原因是坏事:

  1. 因为有些人会写下这样的方法:

    ProcessBatch(true, false, false, true, false, false, true);
    
    Run Code Online (Sandbox Code Playgroud)

    这显然是不好的,因为它很容易混淆参数,你不知道通过查看你指定的内容.只有一个布尔不是太糟糕了.

  2. 因为通过简单的是/否分支来控制程序流可能意味着你有两个完全不同的函数,这些函数以一种笨拙的方式包装成一个.例如:

    public void Write(bool toOptical);
    
    Run Code Online (Sandbox Code Playgroud)

    真的,这应该是两种方法

    public void WriteOptical();
    public void WriteMagnetic();
    
    Run Code Online (Sandbox Code Playgroud)

    因为这些代码可能完全不同; 他们可能不得不进行各种不同的错误处理和验证,甚至可能不同地格式化传出数据.你不能仅仅通过使用Write()甚至Write(Enum.Optical)(尽管如此你可以使用这些方法中的任何一种来调用内部方法WriteOptical/Mag).

我想这只是取决于.除了#1之外,我不会做太多关于它的交易.


Pas*_*ent 13

对我来说,使用布尔值和枚举都不是一个好方法.Robert C. Martin在他的清洁代码提示#12:消除布尔参数中非常清楚地捕获了这一点:

布尔参数大声声明该函数不止一件事.他们很混乱,应该被淘汰.

如果一个方法不止一个,你应该写两个不同的方法,例如在你的情况下:file.append(data)file.overwrite(data).

使用枚举不会使事情更清楚.它没有改变任何东西,它仍然是一个旗帜论点.

  • 这是否意味着接受长度为N的ASCII字符串的函数会执行128 ^ N个事情? (7认同)
  • @Brad show(){mVisible = true} hide(){mVisible = false} (2认同)
  • 我通常建议避免罗伯特·C·马丁的大部分建议 (2认同)

Bor*_*ard 7

枚举更好,但我不会将布尔参数称为"不可接受".有时候抛出一个小布尔值并继续前进会更容易(想想私有方法等)


Chr*_*die 6

布尔可能在具有命名参数的语言中可能没问题,例如Python和Objective-C,因为名称可以解释参数的作用:

file.writeData(data, overwrite=true)
Run Code Online (Sandbox Code Playgroud)

要么:

[file writeData:data overwrite:YES]
Run Code Online (Sandbox Code Playgroud)


Ori*_*rds 5

枚举有一定的好处,但您不应该只是用枚举替换所有布尔值。在很多地方,真/假实际上是表示正在发生的事情的最佳方式。

然而,使用它们作为方法参数有点可疑,因为如果不深入研究它们应该做什么,你就无法看到它们,因为它们让你看到 true/false 的实际含义


[编辑2022年的现状]

在现代 C# 或支持此功能的其他语言中,最好的方法是使用命名参数:

var worker = new BackgroundWorker(workerReportsProgress: true);
Run Code Online (Sandbox Code Playgroud)

如果您的语言不允许命名参数,那么您可能会发现属性也是一个合理的解决方案


[2008年的原始答案留给后人]

属性(尤其是 C#3 对象初始值设定项)或关键字参数(如 ruby​​ 或 python)是一种更好的方法,可以帮助您使用布尔参数。

C# 示例:

var worker = new BackgroundWorker { WorkerReportsProgress = true };
Run Code Online (Sandbox Code Playgroud)

红宝石示例

validates_presence_of :name, :allow_nil => true
Run Code Online (Sandbox Code Playgroud)

Python示例

connect_to_database( persistent=true )
Run Code Online (Sandbox Code Playgroud)

我唯一能想到的布尔方法参数是正确的做法是在 java 中,在那里你既没有属性也没有关键字参数。这是我讨厌java的原因之一:-(