3

我想为我的代码库创建一些不可变对象。真正传达给定类旨在不可变的信息的最佳方式是什么?我应该将所有字段设为最终字段,并在对象构造期间进行初始化吗?(这看起来真的很尴尬......)我应该创建一些不可变接口,并让对象实现它吗?(由于 Java 在这背后没有一些标准接口,我认为他们有其他处理方式。)处理它的标准方式是什么?(如果只是简单地通过在字段周围添加一堆注释来声明它们一旦初始化就不应修改,那也很好。)

4

3 回答 3

8

我应该将所有字段设为最终字段,并在对象构造期间进行初始化吗?

是的。并确保这些类型本身是不可变的,或者当您从 getter 方法返回值时创建副本。并使课程本身成为最终的。(否则你的类本身可能是不可变的,但这并不意味着你的类的任何实例都是不可变的——因为它可能是可变子类的实例。)

(这看起来真的很尴尬……)

如果不知道你觉得它是如何尴尬的,就很难知道该建议什么- 但构建器模式通常很有用。我通常为此使用嵌套的静态类,通常使用静态工厂方法。所以你最终得到:

Foo foo = Foo.newBuilder()
    .setName("asd")
    .setPoints(10)
    .setOtherThings("whatever")
    .build();
于 2013-05-20T23:16:26.423 回答
5

是和不是。将所有字段设为最终字段本身并不能保证。如果您想真正深入了解这一点,那么 Joshua Bloch 在 Effective Java 中的许多章节都涉及不变性和所涉及的考虑因素。Effective Java 中的第 15 项涵盖了大部分内容并引用了其他有问题的项。

他提供了以下五个步骤:

  1. 不要提供任何修改对象状态的方法(称为mutator)。

  2. 确保类不能扩展。

  3. 使所有字段最终。

  4. 将所有字段设为私有。

  5. 确保对任何可变组件的独占访问。

学习如何做到这一切的一种方法是查看语言设计者如何通过查看不可变类(例如 String)的源代码来使类不可变(例如,参见http://grepcode.com/file/repository.grepcode.com /java/root/jdk/openjdk/6-b14/java/lang/String.java)。

于 2013-05-20T23:25:29.213 回答
1

编写一个单元测试,如果您的同事使该类可变,该测试将失败。

使用Mutability Detector,您可以编写如下测试:

import static org.mutabilitydetector.unittesting.MutabilityAssert.assertImmutable;

@Test public void isImmutable() {
    assertImmutable(MyImmutableThing.class)
}

如果有同事出现,例如,向您的班级添加了一个 setter 方法,则测试将失败。您的用例是 Mutability Detector 的核心目的之一。

免责声明:我写的。

于 2013-06-04T21:13:10.540 回答