我在源代码中发现了一些代码,这些代码基本上使用 switch case 遍历枚举的每个可能值并调用适当的函数,该函数根据数据类型返回 Number 对象。
这是一个片段:
case TYPE_16BIT_SIGNED_BE:
measurement = response.getRegisters().getShort(0);
break;
case TYPE_16BIT_UNSIGNED_BE:
measurement = response.getRegisters().getUnsignedShort(0);
break;
case TYPE_16BIT_SIGNED_LE:
measurement = response.getRegisters().getShortLE(0);
break;
现在我的问题是,将此添加到枚举本身被认为是好的还是坏的做法?
这是我的意思的一个例子:
public enum SomethingType {
INT((b) -> {
return b.getInt(0);
}),
DOUBLE((b) -> {
return b.getDouble(0);
}),
LONG((b) -> {
return b.getLong(0);
});
private Function<ByteBuf, Number> getNumber;
SomethingType(Function<ByteBuf, Number> getNumber) {
this.getNumber = getNumber;
}
}
最佳答案
可以发现这种方法得到推广 on all kind of places ,一个可能合理的例子是 state machines .枚举成员在 Scala language 中也很晚才被采用.因此,这显然不是 Java 的怪异功能,而是一个被证明有用的理想功能。我个人在生产代码中多次使用它,尤其是当需要一些静态映射时,从枚举到值或从枚举到函数。它允许结构紧凑、简洁的代码。
此外,IMO 已经令人信服地表明,如果我可以从 the link provided by @johannes-kuhn 中找到一些东西,那么在最初的问题中使用 lambdas 的方式比使用重写的方法更可取。 .
因此,我认为它被认为是好的做法("clean" 在 M.Fowler 和 R.Martin 的意义上)而不是坏的做法。如果没有明确考虑,它应该是。
也就是说,那里有持续的评论 consider enums as such not to be clean ,因为它们引诱您使用不干净的开关语句(准确地说:代码味道,可能与干净相反),引用 M.Fowlers 第一版“Refactoring: Improving the Design of Existing Code”。而且,您知道,正是他创造了“干净”(和“代码气味”)一词。但是在2005 edition他撤回了这一判断。
至于开关:必须考虑当您扩展枚举而忘记扩展所有开关时会发生什么。我和我的同事发现引入单元测试很有用,它循环遍历枚举的所有项目并测试需要确保的内容。该问题为 lambda 增强的枚举提供了另一个论据:在某些情况下,您可以保留开关(switch someValue ... case Enum.x: dosmthg()
)以支持调用映射函数(someValue.dosmthg()
).
至于将此问题归入 Expression Problem 的建议:
经过仔细检查,表达式问题看起来与问题完全无关。来自链接:“表达式问题是旧问题的新名称。目标是通过案例定义数据类型,其中可以向数据类型添加新案例并在数据类型上添加新函数,而无需重新编译现有代码,同时保留静态类型安全(例如,无强制转换)。”
因此一个人不能像建议的那样用方法A和方法B来解决表达式问题,同样的方式一个人不能有Hadwiger–Nelson problem。跟他们。表达式问题本身就是一个问题,也是函数式语言和面向对象语言的难题,每种语言都有不同的解决方案,独立于此处给出的上下文。这是 a java solution shown声称既完整又有效,还有一个 Haskell 解决方案。实际上是一件相当复杂的事情。
关于java - 在被认为是 "clean"的枚举内部提供函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58232195/