我检查了我的代码,发现一些 switch 语句可以重构为多态,但我也注意到我只使用带有枚举的 switch 语句。这是否意味着枚举在 OO 设计中是“邪恶的”并且应该用多态性来消除?
6 回答
首先,Java 实际上有很棒的可以多态使用的枚举。我不是 Java 程序员,所以其他人当然可以举一个很好的例子(我不能)。此外,请考虑多态性通常只是矫枉过正。我也刚刚看过这个演讲,它很棒,但它只提供指导,没有灵丹妙药。
尤其不是所有switch
语句都可以替换。状态机实际上是枚举很有意义的一种情况。我在解析中经常使用状态机。当然,这可以通过设计模式和类多态来完成。但它的代码要多得多,它执行相同的工作,只是速度较慢,它的可读性并不高,而且它是一种只需要在一个地方使用的解决方案,无需任何代码回收。在这里使用子类化根本没有优势。
再说一次,这是一个例外。一般来说,子类化通常是支持它的语言中更好的解决方案。
编辑:我注意到这可能会引起争议。当然有很多很好的封装解析的解决方案,从正则表达式到 Antlr 等解析器生成器框架。他们没有错,除了琐碎的情况外,这些都是更好的解决方案。但是,我经常使用低级代码(显然不是在 Java 中),其中不支持正则表达式并且解析器生成器也会产生开销。
并不是枚举是邪恶的,而是 switch 语句。C++ FAQ Book对此进行了长时间的讨论,但要点是:除了有限的领域——例如对来自设备上的寄存器的数据的解释——一个大开关梳建议你重新使用数据来区分子类型。取而代之的是,您应该只使用子类型,获得编译器的帮助以保持其正确性,并且还意味着当您(不可避免地)更改案例集时编译器将自动添加新案例。
class Sunday extends DayOfWeek {}
class Monday extends DayOfWeek {}
class Tuesday extends DayOfWeek {}
class Wednesday extends DayOfWeek {}
class Thursday extends DayOfWeek {}
class Friday extends DayOfWeek {}
class Saturday extends DayOfWeek {}
枚举很好。
我毫不犹豫地称任何事情为邪恶。这是一个“你想设计这个有多重”的问题。
枚举/开关很好 - 在某些领域。设置类层次结构是问题并不总是需要的开销。但是 case 语句中的代码越多,就越有可能,是的,也许你应该转向更重的方法。
我的经典经验是几年前我为一个班级编写的编译器。我的室友和我上同一个班,我们以两种截然不同的方式接近它。我采用了重 OO 方法,充满了多态性。他采用了重型 C 方法,使用枚举和联合。他的代码大约是我的 LOC 大小的 1/2,他的代码编译速度更快,而且他的代码可以工作。他的代码很灵活,因为它没有过度设计。这对我来说是软件设计方面的宝贵一课。
“这是否意味着枚举在 OO 设计中是“邪恶的”,应该用多态性来消除?”
通常。
switch/enum 结构可以是多种多态结构中的任何一种: State和Strategy是最常出现的两个常见结构。
我认为当值已知且数量很少时,枚举很有用。
此外,枚举在某种程度上被命名为常量。
枚举没有存储任何其他状态(除了它的值)。
当您具有不同的条件状态时,多态性将很有帮助(并且条件需要比依赖单个变量更多的状态)。