让构造函数在封装参数之前对其进行预处理似乎是不好的做法。 然而,很多时候,我们有必要这样做:对作为参数提供的对象进行一些操作,然后才将它们分配给构造对象的属性。为此,我建议使用预构造器,它可以是方法或独立的对象。

Gad Elmaleh等人的《Huge in France》(2019)。
说,这是你的代码:
import java.util.List;
import java.util.Collections;
class Books {
private final List<String> titles;
Books(List<String> list) {
this.titles = Collections.unmodifiableList(list);
}
}
唯一的构造函数期望有一个标题列表,它被封装为this.titles ,以便将来使用。通过JDK的装饰器,它还可以防止任何意外的修改。unmodifiableList到目前为止,一切都很好。现在,我们想让我们的类更聪明一点,让它不仅接受List ,而且接受一个字符串数组。
class Books {
private List<String> titles;
Books(List<String> list) {
this.titles = Collections.unmodifiableList(list);
}
Books(String... array) {
final List<String> list = new ArrayList<>(array.length);
for (final String title : array) {
list.add(title);
}
this.titles = list;
}
}
这段代码有什么问题?那些读过我早期关于OOP的博文的人,最清楚答案。首先,有两个主构造函数,这是另一种不好的做法。 其次,在第二个构造函数中有代码,这也是一个坏主意。
下面是我通常重构这段代码的方法,以解决上述两个问题:
class Books {
private List<String> titles;
Books(List<String> list) {
this.titles = Collections.unmodifiableList(list);
}
Books(String... array) {
this(Books.toList(array));
}
private static List<String> toList(String... array) {
final List<String> list = new ArrayList<>(array.length);
for (final String title : array) {
list.add(title);
}
return list;
}
}
我把这个新的静态方法toList() ,称为预构造器:它只在构建对象的时候使用,而且只从第二构造器中使用。
一个更好的设计方法是建立一个新的类ToList ,它将做同样的事情,但以一种更加声明性和懒惰的方式:
class Books {
private List<String> titles;
Books(List<String> list) {
this.titles = Collections.unmodifiableList(list);
}
Books(String... array) {
this(new ToList(array));
}
}
class ToList<T> implements List<T> {
private final T[] array;
ToList(T... items) {
this.array = items;
}
// All required methods of the List interface
}