将其他数据绑定到枚举

时间:2018-04-05 09:13:07

标签: java enums

众所周知,由于很好的理由,无法扩展枚举。但是我遇到了一个案例,我需要为来自单独库的已实现的枚举的每个值添加一些额外的信息,这个库在我的控制之下但不应包含特定于我正在开发的应用程序的信息。时刻。

实施例

假设我使用一个提供星期几枚举的​​库,如下所示:

public enum DayOfWeek {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY;
}

此外部库中的其他类广泛使用此enum

现在让我们说我们正在编写约会安排应用程序,所以我们想以某种方式将关闭时间与DayOfWeek的每个值联系起来,如果DayOfWeek是我们应用程序的一部分,我们可以只是添加一个字段和一个构造函数,但这不是一个选项。

重要注意事项

  1. 我们选择的解决方案应尽可能像DayOfWeek的实例一样行动。我最好能够传递一个可以用作DayOfWeek的对象,但也包含一个关闭时间。
  2. 缺少值检测。如果在DayOfWeek中添加或删除了一个值(可能是入侵8周的外星人或其他东西),那么我们的实施应尽早失败,直到相应的关闭时间添加到我们的库中。最好是在编译时。
  3. 易于使用。显而易见的是,如何从DayOfWeek为我们的应用程序的新开发人员获得关闭时间。
  4. 可维护性。应该尽可能地困难对我们的实施进行更改。
  5. 易于开发。这是最不重要的,但一个好的解决方案不应该太难实现。
  6. 我尝试了什么

    我对此的初步想法是辅助方法中的一个简单的switch语句如下所示:

    public static String getClosingTime(DayOfWeek day) {
        switch (day) {
        case MONDAY:
        case TUESDAY:
        case WEDNESDAY:
        case THURSDAY:
            return "17:30";
        case FRIDAY:
            return "16:00";
        case SATURDAY:
        case SUNDAY:
            return "Closed";
        default:
            return null;
        }
    }
    

    (为简单起见,返回值为String,它们显然应该是现实世界中的某种对象。)

    这在第3点到第5点成功,但是使用起来很麻烦,因为每次需要关闭时间时都必须调用此方法。

3 个答案:

答案 0 :(得分:3)

如果您不必直接使用DayOfWeek我更喜欢一个界面(与package相同的enum DayOfWeek

public interface IDayOfWeek {

    DayOfWeek getDayOfWeek();
}

并修改您的enum

public enum DayOfWeek implements IDayOfWeek {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;

    @Override
    public DayOfWeek getDayOfWeek() {
        return this;
    }
}

现在,您可以像新的enum一样“

public enum DayOfWeekAndClosingTime implements IDayOfWeek {
    MONDAY(DayOfWeek.MONDAY, "17:30"),
    TUESDAY(DayOfWeek.TUESDAY, "17:30"),
    WEDNESDAY(DayOfWeek.WEDNESDAY, "17:30"),
    THURSDAY(DayOfWeek.THURSDAY, "17:30"),
    FRIDAY(DayOfWeek.FRIDAY, "16:00"),
    SATURDAY(DayOfWeek.SATURDAY, "Closed"),
    SUNDAY(DayOfWeek.SUNDAY, "Closed");

    private final DayOfWeek day;
    private final String closingTime;

    DayOfWeekAndClosingTime(DayOfWeek day, String closingTime) {
        this.day = day;
        this.closingTime = closingTime;
    }

    @Override
    public DayOfWeek getDayOfWeek() {
        return day;
    }

    public String getClosingTime() {
        return closingTime;
    }
}

现在,您可以将其他信息视为一周中的某一天:

public void handleDayOfWeek(IDayOfWeek day) {
    DayOfWeek dayOfWeek = day.getDayOfWeek();
    // do something
    if (day instanceof DayOfWeekAndClosingTime)
        handleClosingTime((DayOfWeekAndClosingTime) day);
}

否定点是DayOfWeekIDayOfWeek

之间的交叉引用

编辑:要检查DayOfWeek中的添加值,您可以添加静态块

static {
    if (DayOfWeekAndClosingTime.values().length != DayOfWeek.values().length)
        throw new IllegalStateException("missing closing times");
}

在那里,您还可以检查包裹day的所有enum是否都是分离的。

编辑2:感谢RobertKock

要获得编译器警告,您可以通过String参数减少构造函数并将其更改为

DayOfWeekAndClosingTime(DayOfWeek day) {
    this.day = day;
    String time = "unknown";
    switch(day) {
        case MONDAY:
        case TUESDAY:
        case WEDNESDAY:
        case THURSDAY:
            time = "17:30";
            break;
        case FRIDAY:
            time = "16:00";
            break;
        case SATURDAY:
        case SUNDAY:
            time = "closed";
            break;
    }
    this.closingTime = time;
}

答案 1 :(得分:2)

这里有点疯狂的想法。您可以扩展您的枚举以接受访问者。

public interface DayOfWeekVisitor<R> {
    public R onMonday();
    public R onTuesday();
    // ...
}

public enum DayOfWeek {
    MONDAY {
        public <R> R accept(DayOfWeekVisitor<R> visitor) { return visitor.onMonday(); }
    },
    // ...
    ;
    public <R> R accept(DayOfWeekVisitor<R> visitor);
}

然后,对于所有依赖DayOfWeek的操作,您将实施特定的访问者:

public class ClosingTimeVisitor extends DayOfWeekVisitor<String> {
    public String onMonday() { return "17:30"; }
    // ...
}

是的,这扩展了枚举 - 但不包含任何特定于应用程序的内容。

它如何符合您的要求?

  1. 我认为dayOfWeek.visit(ClosingTimeVisitor.INSTANCE)是,好吧。不太好但很好。
  2. 缺少值检测。如果我们(希望)被同样拥有Bumbsday的外星人入侵,您可以将onBumbsday添加到DayOfWeekVisitor界面。这将立即迫使您 - 每个编译器错误 - 在您拥有的所有DayOfWeekVisitor实现中实现此方法。
  3. 易于使用。 dayOfWeek.visit(ClosingTimeVisitor.INSTANCE)甚至一些语法糖dayOfWeek.calculate(CLOSING_TIME)对我来说似乎很容易。对于初学者来说这不是常见的事情,但我认为这个概念很容易理解。
  4. 可维护性。评估这一点有点困难。但我觉得没问题。至少比使用Map<DayOfWeek, String>和喜欢保持映射更好。
  5. 易于开发。对我来说似乎很容易。

答案 2 :(得分:0)

对于这些情况,我们遵循以下实施。

public enum DayOfWeek {

    MONDAY(null),
    TUESDAY(null),
    WEDNESDAY(null),
    THURSDAY("17:30"),
    FRIDAY("16:00"),
    SATURDAY(null),
    SUNDAY("Closed");


    private String closingTime;
    public String getClosingTime() {
        return closingTime;
    }


    private DayOfWeek(String closingTime) {
        this.closingTime = closingTime;
    }
}

以下是如何访问它。

DayOfWeek.SUNDAY.getClosingTime(); // it returns "Closed"