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