【问题标题】:Two member enumeration vs. boolean value两个成员枚举与布尔值
【发布时间】:2009-11-06 10:04:20
【问题描述】:

这个问题在我脑海里已经有一段时间了,如果它看起来很主观,很抱歉。在数据对象的公共属性和构造函数中使用 bool 有一些缺点。以下面的代码为例。

使用布尔:

public class Room
{
    public string Name { get; set; }
    public bool Bookable { get; set; }

    public Room(string name, bool bookable);
}

以及这个类的使用

Room r = new Room ("101", true);

这是适当的功能,但是还有另一种实现方式:

使用枚举:

public enum BookingStatus
{
    Bookable,
    NotBookable
}

public class Room
{
    public string Name { get; set; }
    public BookingStatus Bookable { get; set; }

    public Room(string name, BookingStatus bookable);
}

以及这个类的使用

Room r = new Room ("101", BookingStatus.Bookable);

在我看来,这两者在功能上是相同的,但各有优缺点:

  • 设置属性时,Enum 方法更加冗长(您可以仅从代码中推断出 enum 的用法)
  • 可以扩展枚举以支持更多状态(对 API 特别有用)
  • 枚举需要更多的输入(尽管大大减少了)
  • 枚举不能在条件句中使用(即 if (r.bookable)),尽管我知道这很容易解决。

我是否遗漏了什么,完全不合时宜?我不知道为什么这让我如此烦恼,也许我太强迫症了!

【问题讨论】:

  • 意见:这似乎不是最好的例子——如果这是一个真正的是/否问题,那么布尔值是合适的。尽管您应该根据约定正确命名您的属性(即“IsBookable”)——一个更好的例子是一个非是或否问题,例如性别或测量单位等——即使你只识别两个状态(英寸与厘米,或男性与女性),您应该使用枚举,因为这些绝对不是“是或否”问题(即使您可以将它们变成是/否问题,但它们不是,并且每个都可以扩展以支持更多州)。

标签: .net enums boolean


【解决方案1】:

仅仅因为可读性和对代码的理解,我将使用枚举而不是布尔值。

比较BookingStatus.Bookabletrue,当然你会明白更多阅读BookingStatus.Bookable

也像 fforw 提到的那样,以防将来您可能需要添加更多选项,枚举会更容易更改。

【讨论】:

  • 类型安全呢?枚举会阻止任何旧的布尔值被放入枚举参数中。
  • 这也比较好维护。如果发明了一种新的 BookingStatus,则使用枚举时变化会更小
【解决方案2】:

我有可能在未来可能会比最初的两个选项更多,向枚举添加第三个选项比将所有 bool 更改为枚举要少得多。

【讨论】:

  • 这就是他在回答中已经说过的(项目符号列表中的第二点)。
  • “未来计划”方面除外。
【解决方案3】:

对于房产,我可能会同意。但是,在“清洁代码”中,(正确地)表明bools 在用作参数时隐藏了意图。例如,格式化方法可能如下所示:

public void Format(bool pBold, bool pItalic, bool pUnderline)
{ ... }

调用时如下所示:

Format(true, false, true);

相反,它会更具可读性:

public enum BOLD { BOLD, NOT_BOLD }
public enum ITALIC { ITALIC, NOT_ITALIC }
public enum UNDERLINE { UNDERLINE, NOT_UNDERLINE }

public void Format(BOLD pBold, ITALIC pItalic, UNDERLINE pUnderline)
{ ... }

然后调用看起来像:

Format(BOLD.BOLD, ITALIC.NOT_ITALIC, UNDERLINE.NOT_UNDERLINE);

(请记住,这只是 bool 参数如何隐藏意图的示例;可能有更好的方法来实现上述代码。)

在您的特定情况下,请注意两个构造函数调用之间的区别:

// enum; intent is clear
Room r = new Room ("101", BookingStatus.Bookable);

// bool; true what?
Room r = new Room("101", true);

【讨论】:

  • 另外,在使用枚举时,不能将包含粗体值的变量放入“斜体”参数槽。 :) 类型安全。
  • // string; "101" what? 再添加几个字符串,您的位置与使用布尔值相同。所以你会怎么做?你看看方法定义。
  • @Stijn 同意。不阅读方法签名不是不理解方法签名的借口。
【解决方案4】:

在他的书Refactoring 中,Martin Fowler 解释了为什么他认为枚举是一种代码味道,我只能同意。在您的示例中,更好的方法是创建一个抽象 Room 类:

public abstract class Room
{
     public string Name { get; set; }

     public abstract bool Bookable { get; }
}

然后您可以创建派生的 BookableRoom 和 NonBookableRoom 类。

public class BookableRoom : Room
{
    public override bool Bookable
    {
        get { return true; }
    }
}

public class NonBookableRoom : Room
{
    public override bool Bookable
    {
        get { return false; }
    }
}

【讨论】:

  • 强项,以及我在其他地方使用过的方法。我认为这不适用于实体框架之类的东西?但是,它肯定会很好地映射到 SharePoint 列表之类的东西上。
  • 你为什么说这是一个更好的方法?在我看来,它看起来就像在增加复杂性一样。我认为 KISS 原则在这里很合适。
  • 本书提供了全面的描述:)
  • 我同意@nightcoder 的观点,并且对选择这个答案感到困惑。 OP 是否担心枚举不会是一种复杂而冗长的 足够 方式来翻转一个位?所以我们应该将每个对象类型的每个运行时状态烘焙到我们的源代码中吗? Martin Fowler 为这种做法辩护说了什么?
  • 那么当你有多个状态属性时你会怎么做?添加更多课程?添加提供所有可能状态组合的类?
猜你喜欢
  • 1970-01-01
  • 2011-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-10
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
相关资源
最近更新 更多