在Java中,似乎公共构造函数总是一个糟糕的编码实践

Ada*_*ent 1 java coding-style

可能重复:
考虑提供静态工厂方法而不是构造函数

这可能是一个有争议的问题,可能不适合这个论坛(所以如果你选择关闭这个问题,我不会被侮辱).

看来Java的当前功能似乎没有理由构建构造器public...... 永远.友情,private,protected是确定的,但public没有.

似乎提供public static创建对象的方法几乎总是更好的主意.每个Java Bean序列化技术(JAXB,Jackson,Spring等......)都可以调用受保护或私有的无参数构造函数.

我的问题是:

  • 我从来没有见过这种做法在任何地方下令或写下来?也许布洛赫提到它,但我不拥有的是书.
  • 是否有一个用例除了可能不是超级DRY我错过了?

编辑:我解释为什么静态方法更好.

0.1.对于一个你得到更好的类型推断.例如,请参阅Guava的http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained

0.2.作为该类的设计者,您可以稍后使用静态方法更改返回的内容.

0.3.处理构造函数继承很痛苦,特别是如果你必须预先计算某些东西.0.4.更多理由:https://stackoverflow.com/a/3852556/318174

我应该发布这是针对公共API的代码.我经常违反各种规则(比如使用直接现场访问)进行单元测试,方便,因为我很懒.因此,当我的意思,我的意思是你把它释放到野外.

Bhe*_*ung 7

如果以下是该方法的外观

public class MyClass {

    private MyClass() { }

    public static MyClass getInstance() {
        return new MyClass();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后宁愿有一个公共的无参数构造函数.

如果我必须调用这样的方法,它会让我觉得它正在做一些事情来构建对象,但实际上并非如此.

我不认为有一个方法除了调用构造函数本身之外什么都不做.


Pet*_*rey 5

简而言之,静态工厂很酷,而且有其用途,但是有些API陷入了在各处使用它们的陷阱,即使它们没有增加价值而只是增加了复杂性。

静态工厂在Java中运行良好的一个例子是EnumSet,它具有许多命名的构建器,不能自然地实现为重载的构造器。

例如,即使它们具有相同的参数,它们也不会做相同的事情。

EnumSet.of(E1, E3);
EnumSet.range(E1, E3);
Run Code Online (Sandbox Code Playgroud)

EnumSet还会根据枚举中的元素数量返回两个不同的实现。

    if (universe.length <= 64)
        return new RegularEnumSet<>(elementType, universe);
    else
        return new JumboEnumSet<>(elementType, universe);
Run Code Online (Sandbox Code Playgroud)

不幸的是,EnumMap不能做类似的事情,因此只有一个实现。


.1。首先,您可以获得更好的类型推断。例如见番石榴的

所以番石榴有类似的方法

List<TypeThatsTooLongForItsOwnGood> list = Lists.newArrayList();
Map<KeyType, LongishValueType> map = Maps.newLinkedHashMap();
Run Code Online (Sandbox Code Playgroud)

在Java 7中

List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<>();
Map<KeyType, LongishValueType> map = new LinkedHashMap<>();
Run Code Online (Sandbox Code Playgroud)

较短的时间,您不需要学习任何新方法,如果不需要再次检查类型,则可以执行Java 6。

List<TypeThatsTooLongForItsOwnGood> list = new ArrayList();
Map<KeyType, LongishValueType> map = new LinkedHashMap();
Run Code Online (Sandbox Code Playgroud)

在番石榴你有

Set<Type> copySet = Sets.newHashSet(elements);
List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");
Run Code Online (Sandbox Code Playgroud)

内置方法在哪里

Set<Type> copySet = new HashSet<String>(elements);
List<String> theseElements = Arrays.asList("alpha", "beta", "gamma");
Run Code Online (Sandbox Code Playgroud)

如果<String>从HashSet中删除,则会失去类型安全性,但是鉴于大多数体面的IDE会为您自动完成此代码,因此您实际上将不会保存任何类型。

.2。作为类的设计者,您以后可以更改使用静态方法返回的内容。

我要说的是YAGNI,在实践中很难透明地显着更改实现。您完全不必向后兼容,而无需重新构建或重新测试代码就可以替换掉。

.3。处理构造函数继承非常麻烦,特别是如果您必须预先计算某些内容时。

这是真的,但很少见。对于这种情况,我通常有一个用于复杂构造的生成器类,仅靠因子方法不能解决问题。


值得考虑的是,Java库中的大多数类都使用构造函数而不是静态工厂。我能想到的唯一类是在哪里使用了构造函数,但后来改为在可能的情况下使用静态工厂是自动装箱包装器类。语言隐藏了知道调用哪个工厂方法的复杂性。

鉴于Java的当前功能,似乎没有理由公开构造函数。友善,私人,受保护都可以,但公众可以。

仅仅因为您可以做某事就不是一个好主意。

例如,您可以将所有类,方法和变量设置为1或2个字符长(您不必使用3个字母或更长的名称,有些人认为这样做更好),但这并不是一个好主意。

顺便说一句,如果您查看了常见的UNIX命令,其中许多都是两个字符。;)

提供创建对象的公共静态方法似乎几乎总是一个更好的主意。

除非您更喜欢简单性,而不要使代码不必要地变得复杂。

我从未见过此法令在任何地方颁布或写下来?

我也没有。可能是因为这不是一个好主意。恕我直言。

除了可能不是我错过的超级DRY之外,还有其他用例吗?

您尚未说出这样做的充分理由,这就是足够的理由不对我这样做。;)

  • +1仅仅因为您可以做某事就不是一个好主意。 (2认同)