我正在阅读 Effective Java 中创建不可变类时需要遵循的具体指南.
我读到在不可变类中方法不应被覆盖,否则被覆盖的方法可能会改变方法的行为。以下是 java 中可用于解决此问题的设计方法:-
我们可以将类标记为 final,但根据我的理解,它有一个缺点,即它使类不可扩展。
其次是使个别方法成为 final方法,但除了我们需要单独将每个方法标记为 final方法以防止覆盖之外,我没有其他缺点。
根据书本,更好的方法是将构造函数设为私有(private)或包私有(private),并提供用于创建对象的公共(public)静态工厂方法。
我的问题是:即使我们在类中包含私有(private)或默认构造函数,它也不能再在同一个包中扩展(在包私有(private)构造函数的情况下在其他包中),它有与第一个相同的问题.它如何被认为是比以前的方法更好的方法?
最佳答案
不可变对象(immutable对象)不应该是可扩展的。为什么?
因为扩展它将允许直接访问字段(如果它们是 protected
将允许编写更改它们的方法),或者添加可能可变的状态。
假设我们编写了一个类 FlexiblyRoundableDouble
来扩展 Double
,它有一个额外的字段 roundingMode
让我们选择一个“舍入模式”。您可以为此字段编写一个 setter,现在您的对象是可变的。
你可以争辩说,如果所有的方法都设置为final,你就不能改变对象的原始行为。唯一可以访问您的 roundingMode
字段的方法是新方法,如果您将对象分配给 Double
变量,则这些方法不能多态使用。但是当一个类的契约(Contract)说它是不可变的时,你就可以根据它做出决定。例如,如果您为具有 Double
字段的类编写 clone()
方法或复制构造函数,您知道您不需要深度复制 Double
字段,因为它们不会改变它们的状态,因此可以在两个克隆之间安全地共享。
此外,您可以编写返回内部对象的方法,而不必担心调用者随后会更改该对象。如果该对象是可变的,则您必须制作它的“防御性副本”。但如果它是不可变的,则返回对实际内部对象的引用是安全的。
但是,如果有人将 FlexiblyRoundableDouble
分配给您的其中一个 Double
字段,会发生什么情况?该对象将是可变的。 clone()
会假设它不是,它将在两个对象之间共享,甚至可能由方法返回。然后,调用者可以将其转换为 FlexiblyRoundableDouble
,更改字段...这将影响使用同一实例的其他对象。
因此,不可变对象(immutable对象)应该是最终的。
这一切都与构造函数问题无关。对象可以通过公共(public)构造函数安全地保持不变(如 String
、Double
、Integer
和其他标准 Java 不可变对象(immutable对象)所证明的那样)。静态工厂方法只是利用对象不可变这一事实的一种方式,并且其他几个对象可以安全地持有对它的引用,从而创建更少的具有相同值的对象。
关于java - 创建不可变类的最佳设计方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29470658/