【问题标题】:Using Enum to hold object constants使用 Enum 保存对象常量
【发布时间】:2016-05-16 16:45:46
【问题描述】:

所以我最近学到了很多东西,所以我要回过头来重构以前课程中的作业,以使用良好实践来实施它们。一项作业让我们实现了一个包含 Course 对象数组的 Planner 对象。我正在尝试创建一些课程常量,这样我就可以访问一些流行的课程,而不必每次都创建全新的对象,这样我就可以轻松地访问它们而无需经历课程构建过程。我对枚举没有太多经验,而且我似乎找不到任何关于如何实际使用枚举来存储对象常量的信息。我最初想让它们在 Course 类中成为常量,但 Effective Java 坚持应该在这种情况下使用枚举。我的实现是否有意义?我应该如何制作包含 Course 常量的枚举,以便我可以实际检索它们?我使用 Builder 方法来创建课程。

public enum Courses {
    CSE_114, CSE_214, CSE_219, CSE_215;

    private final static Course CSE_114_COURSE = new Course
        .Builder("Computer Science 1", "Paul Fodor", 114)
        .section((byte)1).department("CSE").build();

    private static final Course CSE_214_COURSE = new Course
        .Builder("Data Structures", "Ahmad Esmaili", 214)
        .section((byte)1).department("CSE").build();

    private static final Course CSE_219_COURSE = new Course
        .Builder("Software Development", "Richard McKenna", 219)
        .section((byte)1).department("CSE").build();

    private static final Course CSE_215_COURSE = new Course
        .Builder("Foundations of CS", "Paul Fodor", 215)
        .section((byte)1).department("CSE").build();

    public static Course get(Courses c) {
        switch(c) {
            case CSE_114: return CSE_114_COURSE;
            case CSE_214: return CSE_214_COURSE;
            case CSE_219: return CSE_219_COURSE;
            case CSE_215: return CSE_215_COURSE;
            default: throw new IllegalArgumentException("Course does not exist.");
    }
}
}

【问题讨论】:

  • 只是出于好奇,您为什么不使用 Map 而不是使用枚举?
  • @AndrewWilliamson 我只是对如何使用枚举来保存一堆常量感兴趣,但最后我意识到枚举根本没有必要。我从来没有真正使用过地图。我理解这个概念,这实际上听起来是个好主意,因为我可以按名称检索课程并将其设置为 O(1)。如果我要使用地图,你认为哪里是合适的地方?在像以前一样的 CourseManager 课程中?
  • 您可以只使用 Map 而不是 CourseManager 类。如果你想要额外的功能,比如从文件或网络加载,那么你肯定会想要创建一个特定的 CourseManager 类,它可能包含一个 Map 和一些其他实用程序方法。

标签: java enums constants


【解决方案1】:

您实际上可以将枚举视为对象:

public enum Course {
    CSE_114("Computer Science 1", "Paul Fodor");

    public final String room;
    public final String lecturer;

    private Course(room, lecturer) {
        this.room = room;
        this.lecturer = lecturer;
    }
}

因为它是一个枚举,所以在编译时必须知道所有值。这是由 Java 语言强制执行的,它要求枚举构造函数是私有的。

虽然这适用于您的情况,但我不建议这样做 - 事实上,我根本不建议使用枚举。枚举表示一组固定的、已知的值。如果你想在运行时创建更多的课程,那么枚举是不完整的,这与枚举的定义相矛盾。

相反,我建议您使用 CourseManager。创建一个类,其中包含所有已知课程的集合。然后,当您需要一门课程时,您可以通过名称请求它。

Course cs114 = courses.get("CS 114");

您还可以更进一步,从一个文件中实例化 CourseManager,该文件包含一个基本格式(如 JSON)的课程列表。

【讨论】:

  • 是的,新课程将在运行时创建,因为重点是允许用户创建自定义课程并将其添加到计划器。我当然不会枚举每一门课程,所以现在我明白只有在你知道所有值时才应该使用枚举。但是为什么创建一个类来保存 Course 常量比将常量放在 Course 类中更好呢?我不能像您在 Course 类中展示的那样创建一个静态 get 方法来获取特定的 Course 实例吗?
  • 创建一个类来保存课程有两个主要优点 - 它可以从文件、数据库或其他来源实例化,您可以添加或重命名课程,“get”方法仍然有效正如预期的那样。
【解决方案2】:

这不是一个糟糕的实现,但我认为有一个更好的解决方案:在枚举定义中添加一个抽象方法。

public enum Courses {
    CSE_114 {
        public Course getCourse() {
            return CSE_114_COURSE;
        }
    }
    ...

    private final static Course CSE_114_COURSE = new Course
        .Builder("Computer Science 1", "Paul Fodor", 114)
        .section((byte)1).department("CSE").build();

    ...

    public abstract Course getCourse();

}

这样您就可以通过Courses.CSE_114.getCourse() 访问任何课程对象,并且您还强制每个enum 都有一个课程(假设您添加了一个枚举常量但忘记在get 方法中添加它。我的方式是提议使这种情况毫无意义)

【讨论】:

  • 这里的特定于常量的方法比使用 switch-case 块的建议方法要好。但实际上,封装到 Course 对象中的数据应该直接与枚举常量本身相关联,以产生更好的解决方案。
  • 是的,你是对的。我提出的解决方案将是第一步,理想情况下,它会演变成更好的解决方案(您的)
【解决方案3】:

您将枚举常量与静态常量混合在一起。从枚举类中获取这些课程和课程选择。或者你可以使用像 Andrew Williamson 展示的东西。只是不要将静态常量与枚举混合。静态常量不属于枚举类。 Enum 类有一组固定的值,这就是它的作用结束的地方。使用这些枚举的所有其他逻辑都应该在其他地方完成

【讨论】:

  • “Enum 类有一组固定的值,这就是它的作用结束的地方......” ...我不能同意。枚举在各个方面都是一个普通的 java 类,除了它具有更精细的语义。 Java 丰富的枚举类型应该将行为和值与枚举常量相关联,只要这样做是有意义的。这就是使 Java 枚举类型比其他一些语言中的枚举强大得多的部分原因。上面威廉姆森提出的将值与常数相关联的解决方案更加正确。
  • 我同意 Andrew Williamson 的方法。但是我的重点是适当地使用 enum 类,发问者只是滥用 enum 类使其成为 java 类,而 enum 的含义是使事情更加类型安全.. 在枚举中添加静态常量绝不是一个好主意,即使 java 允许这样做
  • 你说得对,我把它们弄混了,不知道枚举应该包含所有可能的值,而不仅仅是一些。只是每次提到常量时,我​​都会看到枚举被提出以及如何使用它们来包含常量。
猜你喜欢
  • 2015-09-09
  • 1970-01-01
  • 2018-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多