【问题标题】:Do enums violate open/closed principle Java? [closed]枚举是否违反 Java 的开放/封闭原则? [关闭]
【发布时间】:2016-07-15 09:59:09
【问题描述】:

在 java 中,如果我们正在使用一个枚举,并且最终我们想在该枚举中添加/删除一个属性,因此它的用法,我们违反了可靠原则中的开放/封闭原则。

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

【问题讨论】:

  • 您能详细说明一下吗?我们是如何违反这些原则的?
  • 打开/关闭是一个原则,而不是需要始终遵循的教条。
  • @MarkRotteveel 但这在大多数情况下让生活变得轻松,对吧?特别是尝试扩展其他一些代码?
  • 不,为自己着想会使生活变得轻松,不要在没有理解或反思的情况下跟随他人的想法。
  • @MarkRotteveel 那么你的解释是什么?

标签: java oop enums solid-principles open-closed-principle


【解决方案1】:

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

如果你想要一些可以扩展的东西,你总是可以使用一个类或者构建你自己的可以扩展的"type-safe enumeration"

关于语言。我选择使用术语 apply 而不是 violate,因为原则和许多良好实践一样,都有应用它们有意义的上下文。违反(对我来说)意味着一种情况需要使用原则,但没有使用或没有正确实施。 它不适用 意思是它在锡上所说的,该原则在当前上下文中没有任何用处或无法应用,否则会与其他具有更强效力的原则相悖.. . 在上下文中:)。

编辑

我认为 Enums 不违反 OCP 的另一个原因(现在我使用这个词 violate :D),因为 OCP 并不意味着所有的类和方法都可以扩展,而是一个尽职尽责的开发人员就将这些扩展点放在哪里做出明智的决定。在Enum 的情况下,开发人员明白没有必要扩展可能的值,而且添加新值会造成破坏,因为现有代码不知道如何处理新值。所以他/她决定完全关闭课程并且不提供扩展点。这同样适用于final 的任何其他类。 final 类不违反 OCP,而是(或理想情况下)开发人员决定不允许扩展它。

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

再补充一点,我看到一些库没有正确实现 OCP(Tapestry 5)并且超出了最终的需要,这使得它们成为可以使用的 PITA。或者只是不关闭任何东西,这会使一些开发人员犯错误,因为他们不了解库的更详细的细节,并且搞砸了不变量。

【讨论】:

  • 如果是这样,显然没有问题。 :)
  • 我不完全理解你的评论......但让我想知道我的回答是否听起来很傲慢。我希望不是!!
  • 由于枚举不能扩展,它们违反了OCP。枚举应该是完整的并且不需要扩展,这意味着它们可以OK违反OCP;但他们仍然违反它。
  • @jaco0646 也许这是语言问题。我会说它不适用而不是违反原则。但同样,它是语言,因此不完美。
  • 因此,如果我使用一些 ENUM 作为 PAymentType,并且到目前为止它具有“DEBIT_CARD,CREDIT_CARD”,然后如果我引入新的付款类型“CASH”,现在如果我将其添加到 ENUM,是吗?修改枚举时违反 OCP?
【解决方案2】:

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

Java 中“更好地使用枚举”是让它们实现一个接口,并让客户端依赖于该接口而不是枚举实现,因为该接口不违反开放/封闭原则。


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

如果一个模块可供其他模块使用,则称该模块已关闭...在实现级别,模块的关闭还意味着您可以编译它,也许将其存储在库中,并使其可用供其他人(其客户)使用。

--Bertrand Meyer,《面向对象的软件构建》第 2 版。第 57 页

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

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


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

【讨论】:

  • 这正是我的想法。 :)
  • 问题是如何存储值列表并一一处理?例如 enum Fruits {apple, pear,banana} switch(Fruits) (case apple: gnerateApple(); break, .....) 这样我总是需要更新 Enum,并使用 switch 函数,加上添加某处方法生成“某物”。该问题的任何模式?
【解决方案3】:

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

只要 Enum Types 必须是一组众所周知的值,就不应该这样写:

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

出于三个原因:

1) Java 不允许这样做。

2) 鸡绝不是水果

3) 水果不再是一套众所周知的完整价值观

如果您使用 Enum 定义,例如,太阳系的行星并且发现了新行星或旧行星失去其状态(或被外星人摧毁),则可以修改您的类以调整新要求.

【讨论】:

  • 这没有回答“枚举是否违反 OCP?”这个问题。是还是不是?
猜你喜欢
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-17
  • 2010-10-08
  • 1970-01-01
相关资源
最近更新 更多