枚举是否违反 open/closed 原则 Java?

Do enums violate open/closed principle Java?

在 java 中,如果我们正在使用一个枚举并且最终我们想要 add/remove 一个属性 to/from 该枚举,因此它的用法,我们违反了 open/closed原则中的原则。

如果是这样,枚举的更好用法是什么?

答案是 ,因为 OCP 不适用于(也不能应用于)枚举。枚举应该是完整的(包含所有可能的值)和静态的(static = final,不可变)。您可以将它们视为一小部分有限的值对象。

如果您想要可以扩展的东西,您可以随时使用 class 或构建您自己的可以扩展的 "type-safe enumeration"

关于语言。我选择使用术语 apply 而不是 violate,因为原则和许多良好实践都具有适用它们的上下文。违反(对我而言)意味着情况需要使用原则,但没有使用或没有正确实施。 它不适用 意思是它在罐头上说的,该原则在当前上下文中没有用处或不能应用,否则会违背其他更强大的原则强制...在上下文中 :).

编辑

我认为枚举不违反 OCP 的另一个原因(现在我使用 violate :D),因为 OCP 并不意味着所有 classes 和方法可以被扩展,而是一个尽责的开发人员对放置这些扩展点的位置做出明智的决定。在 Enum 的情况下,开发人员明白没有必要扩展可能的值,而且添加新值会造成损害,因为现有代码不知道如何处理新值。所以 he/she 决定完全关闭 class 并且不提供扩展点。这同样适用于任何其他 class 即 finalfinal class 没有违反 OCP,而是(或理想情况下)开发人员决定不允许扩展它。

这与我之前提到的类似,枚举就像一个小的、有限的值对象集。 VO 是不可变的和封闭的,因此它们不违反 OCP。

要补充更多,我看到一些库没有正确实现 OCP (Tapestry 5) 并且制作了超出需要的最终版本,这使它们成为 PITA 以供使用。或者只是不关闭任何东西,这让一些开发人员犯了错误,因为他们不了解库的更精细的细节,并且弄乱了不变量。

Open/Closed 以及所有 SOLID 原则旨在简化重构和理解代码。您应该根据上下文使用它。

只要枚举类型必须是一组众所周知的值,您就不应该这样写:

enum Fruits {apple, pear, banana}
enum Food extends Fruits {chicken}

三个原因:

1) Java 不允许。

2) 鸡绝不是水果

3) 水果不再是众所周知的完整值

如果您使用 Enum 来定义,例如,太阳系的行星,并且发现了一个新行星或一个旧行星失去了它的地位(或被外星人摧毁),那么修改您的 class调整新要求。

答案是。所有 Java 枚举都违反了 Open/Closed 原则,因为它们不能在不修改的情况下扩展。

Java 中“更好地使用枚举”是让它们实现一个接口,并让客户端依赖于该接口而不是枚举实现,因为该接口不违反 Open/Closed 原理.


不要妄下结论说如果枚举违反了 OCP,那么我们就不应该被允许使用它们。我想澄清这个答案,提醒一下,根据定义,OCP 仅适用于面向客户的代码,即 public/exposed 的代码。 OCP不限制实现细节。

A module is said to be closed if it is available for use by other modules... At the implementation level, closure for a module also implies that you may compile it, perhaps store it in a library, and make it available for others (its clients) to use.

--Bertrand Meyer, Object-Oriented Software Construction 2nd ed. page 57

因此,将枚举用作应用程序内部的一部分 API 可以完全避免 OCP。它只是作为外部 API 的一部分,枚举应该通过接口抽象出来。

考虑一下,由于枚举是一个具体的实现,因此仅通过接口公开它可以像满足 OCP 一样满足依赖倒置原则。即使您认为直接公开枚举以某种方式避开了 OCP,它仍然会创建具体的依赖关系,这违反了 DIP。


还要考虑@MarkRotteveel 的评论,“Open/closed 是一个原则,而不是需要始终遵循的教条。”