众所周知,由于很好的理由,无法扩展枚举。但是我遇到了一个案例,我需要为来自单独库的已实现的枚举的每个值添加一些额外的信息,这个库在我的控制之下但不应包含特定于我正在开发的应用程序的信息。时刻。
假设我使用一个提供星期几枚举的库,如下所示:
public enum DayOfWeek {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
}
此外部库中的其他类广泛使用此enum
。
现在让我们说我们正在编写约会安排应用程序,所以我们想以某种方式将关闭时间与DayOfWeek
的每个值联系起来,如果DayOfWeek
是我们应用程序的一部分,我们可以只是添加一个字段和一个构造函数,但这不是一个选项。
DayOfWeek
的实例一样行动。我最好能够传递一个可以用作DayOfWeek
的对象,但也包含一个关闭时间。DayOfWeek
中添加或删除了一个值(可能是入侵8周的外星人或其他东西),那么我们的实施应尽早失败,直到相应的关闭时间添加到我们的库中。最好是在编译时。DayOfWeek
为我们的应用程序的新开发人员获得关闭时间。我对此的初步想法是辅助方法中的一个简单的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点成功,但是使用起来很麻烦,因为每次需要关闭时间时都必须调用此方法。
答案 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);
}
否定点是DayOfWeek
和IDayOfWeek
编辑:要检查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"; }
// ...
}
是的,这扩展了枚举 - 但不包含任何特定于应用程序的内容。
它如何符合您的要求?
dayOfWeek.visit(ClosingTimeVisitor.INSTANCE)
是,好吧。不太好但很好。onBumbsday
添加到DayOfWeekVisitor
界面。这将立即迫使您 - 每个编译器错误 - 在您拥有的所有DayOfWeekVisitor
实现中实现此方法。dayOfWeek.visit(ClosingTimeVisitor.INSTANCE)
甚至一些语法糖dayOfWeek.calculate(CLOSING_TIME)
对我来说似乎很容易。对于初学者来说这不是常见的事情,但我认为这个概念很容易理解。Map<DayOfWeek, String>
和喜欢保持映射更好。答案 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"