我在源代码中找到了一些代码,该代码基本上使用开关大小写来遍历枚举的每个可能值,并调用基于数据类型返回 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;
}
}
人们可以在各种地方找到这种方法的推广,一个可能防御的例子是状态机。枚举成员在很久以后也被斯卡拉语言采用。因此,它显然不是Java的怪胎功能,而是一个被证明是有用的理想功能。我个人一次又一次地在生产代码中使用它,特别是当需要一些静态映射时,从枚举到值或从枚举到函数。它允许结构紧凑、简洁的代码。
此外,IMO 已经令人信服地表明,如果我可以从 @johannes-kuhn 提供的链接中清除一点,那么以最初问题中提出的方式使用 lambda 比使用覆盖方法更可取。
因此,我确实认为这被认为是好的做法(M.Fowler和R.Martin意义上的“干净”),而不是坏的做法。如果没有明确考虑,它应该是。
也就是说,有一些持续的评论认为枚举是不干净的,因为它们引诱你使用不干净的switch语句(准确地说:代码气味,也许与干净相反),指的是M.Fowlers的第一版“重构:改进现有代码的设计”。而且,你知道,是他创造了“干净”(和“代码气味”)这个词。但在2005年版中,他收回了这一判断。
至于开关:必须考虑当您扩展枚举并且忘记扩展所有开关时会发生什么。我和我的同事发现引入单元测试很有用,它循环遍历枚举的所有项目并测试需要确保的内容。这个问题为由lambdas增强的枚举产生了另一个论据:在某些情况下,您可以省去开关(切换一些值...案例 Enum.x:
dosmthg()) 赞成调用映射函数 (someValue.dosmthg()
)。
至于将这个问题归入表达问题的建议:
仔细检查,看起来表达式问题与问题完全无关。来自链接:“表达式问题是旧问题的新名称。目标是按大小写定义数据类型,其中可以向数据类型添加新事例,并在数据类型上添加新函数,而无需重新编译现有代码,同时保留静态类型安全性(例如,无强制转换)。
因此,不能像建议的那样用方法A和方法B出现表达式问题,就像不能有哈德维格-纳尔逊问题一样。表达式问题本身就是一个问题,也是函数式语言和面向对象语言的难题,每种语言都有不同的解决方案,独立于此处给出的上下文。这是一个Java解决方案,它声称既完整又有效,还有一个Haskell解决方案。从本质上讲,这是一件相当复杂的事情。