不可变性和可读性

6
我一直在阅读 Joshua Bloch 的 Effective Java,注意到两个点,这些点我在我的工作中也遇到了。
第一点:使用setter方法让代码更易读。在他的例子中,我们有一个具有非常多参数的类构造器。当人们实例化该类时,很难知道所有参数的含义。因此,他建议创建一个最简构造器,并为所有其他选项添加setter方法,所以你可以用以下代码替代:
MyClass clazz = new MyClass(a, b, c, d, e, f, g);
改成:
MyClass clazz = new MyClass(a, b, c); clazz.setDitto(d); clazz.setEcho(e); clazz.setFunzies(f); clazz.setGumballs(g);
对于我这个强烈支持可读性代码的人来说,我非常喜欢这个建议。
第二点:总体上,他建议使用不可变类。他详细解释了为什么使用不可变类比拥有可能处于多种状态的类更好。我可以肯定地说,他让我相信了这个想法,我迫不及待地想让我编写的大多数类都是不可变的,除了……
当你有一个具有巨大构造器的不可变类时会发生什么?你不能为它创建setter方法,那样会破坏不可变性。我试图快速浏览整本书,但我认为他没有涉及解决此问题的方法。
有可能会使用一次性使用setter方法,但即使它只是在尝试后抛出异常,一个可变性类仍然拥有setter方法,这让人感到沮丧。
是否有任何好的想法来处理这个问题?我目前在工作中面临这个问题,我有一个具有巨大构造器的不可变类,我想将其重构为更易读的内容,而不破坏其不可变性。

一个有用的概念似乎是让可变和不可变类从一个共同的抽象基类派生出来(该基类公开了所有属性的getter)。不可变类的构造函数可以接受基类的参数。但是,不确定如何允许可变类使用读写属性隐藏抽象只读属性,而不创建实现只读属性的中间类。 - supercat
4个回答

14

一种选择是提供一个单独的构建器类,该类提供setter方法,并负责构建实际的对象。

在Bloch的《Effective Java》第二版中,第2项说明了一个不可变类的情况。其关键思想如下:

  • 构建器为每个选项都有一个可变字段。
  • 构建器将自身作为不可变类构造函数的单个参数传递。

1
在我看来,带有可链接方法的+1构建器实际上可以提高可读性,而具有void设置方法的可变对象则不能。 - ColinD
同意。Bloch在上述示例构建器中包含可链接的setter。 - Andy Thomas
太棒了!我简直不敢相信我错过了那个。我大多数时间都在浏览不可变性部分,完全忘记回头检查构造函数了。 - Noj

3

介绍参数对象,也许是个不错的选择?它可以在某种程度上解决问题,但或许有些用处。你的参数对象不需要任何方法,只需保存数据,并在设置时使用它,而不是你真正的类。然后,你的真正类通过参数对象在构造函数中进行初始化。


2

非常正确,流畅的接口似乎与构建器是相同的概念。非常酷的概念。我简直不敢相信我错过了它。 - Noj

0
如何创建一个抽象基类,该基类支持所有属性的获取器但不支持设置器;创建一个衍生密封的“不可变”类,其构造函数接受一个基类对象;再创建一个衍生的可变类,该类包括所有属性的设置器?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接