隐藏静态创建方法背后的构造函数?

时间:2010-10-04 00:28:19

标签: java

我最近发现了一种在Google GuavaProject Lombok中创建对象的新实例的有趣方法:隐藏静态创建方法背后的构造函数。这意味着您不是new HashBiMap(),而是HashBiMap.create()

我的问题是为什么?隐藏构造函数有什么好处?对我来说,我认为这样做绝对没有优势,它似乎打破了基本的对象创建原则。自开始以来,您使用new Object()创建了一个对象,而不是某些Object.createMe()方法。这几乎就像为了创建方法而创建一个方法。

这样做会有什么好处?

9 个答案:

答案 0 :(得分:27)

为什么您可能更喜欢静态工厂方法而不是公共构造函数,原因有很多。您可以阅读Effective Java, Second Edition中的第1项进行更长时间的讨论。

  1. 它允许方法返回的对象类型与包含该方法的类的类型不同。实际上,返回的类型可能取决于参数。例如,如果emum类型的元素非常少,则EnumSet.of(E)将返回不同的类型,如果枚举类型包含许多元素(在此特定情况下为编辑:,则会改善常见情况的性能) enum没有很多元素)
  2. 它允许缓存。例如,Integer.valueOf(x)默认情况下,如果x介于-128和127之间,则会使用相同的值x多次调用返回相同的对象实例。
  3. 它允许您拥有命名构造函数(如果您的类需要许多构造函数,这可能很有用)。例如,请参阅java.util.concurrent.Executors
  4. 中的方法
  5. 它允许您创建一个概念上简单但实际上非常强大的API。例如,Collections中的静态方法隐藏了许多类型。他们可以创建许多公共类,而不是拥有许多静态方法的Collections类,但对于熟悉或记住该语言的新手来说,这将更难。
  6. 对于泛型类型,它可以限制您需要输入的内容。例如,您可以执行List<String> strings = new ArrayList<String>()而不是在Guava中键入List<String> strings = Lists.newArrayList()newArrayList方法是通用方法,并且推断了泛型类型。)
  7. 对于HashBiMap,最后一个原因是最有可能的。

答案 1 :(得分:7)

这通常是因为create()方法实际实例化的类可能与调用方法的类型不同。即工厂模式,其中create()方法返回适合给定当前上下文的特定子类。 (例如,当currrent环境是Windows时返回一个实例,而当它是Linux时返回另一个实例)。

答案 2 :(得分:6)

与构造函数不同,静态方法可以具有方法名称。这是我最近写的一个有用的课程:

/**
 * A number range that can be min-constrained, max-constrained, 
 * both-constrained or unconstrained.
 */

public class Range {
  private final long min;
  private final long max;
  private final boolean hasMin;
  private final boolean hasMax;

  private Range(long min, long max, boolean hasMin, boolean hasMax) {
    // ... (private constructor that just assigns attributes)
  }

  // Static factory methods

  public static Range atLeast (long min) {
    return new Range(min, 0, true, false);
  }

  public static Range atMost (long max) {
    return new Range(0, max, false, true);
  }

  public static Range between (long min, long max) {
    return new Range(min, max, true, true);
  }

  public static Range unconstrained () {
    return new Range (0, 0, false, false);
  }
}

你不能仅使用构造函数来执行此操作,因为atLeastatMost将具有完全相同的签名(它们都需要一个长)。

答案 3 :(得分:3)

这称为Factory方法模式。工厂属于班级本身。 Wikipedia describes it pretty well但这里有几个片段。

  

工厂方法在工具包和框架中很常见,其中库代码需要创建类型的对象,这些类型可以由使用框架的应用程序进行子类化。

     

并行类层次结构通常要求来自一个层次结构的对象能够从另一个层次结构创建适当的对象。

答案 4 :(得分:0)

SomeClass.create()可以从缓存中提取实例。如果没有一些恶作剧,new SomeClass()就不会这样做。

create()也可以返回SomeClass的任意数量的实现。基本上是一种工厂类型的交易。

答案 5 :(得分:0)

虽然不适用于此特定代码示例,但将构造函数隐藏在静态方法后面的做法是Singleton Pattern。当您想要确保在整个过程中创建并使用该类的单个实例时,可以使用此方法。

答案 6 :(得分:0)

使用此工厂方法模式有很多原因,但Guava使用它的一个主要原因是它允许您在创建新实例时避免使用类型参数两次。比较:

HashBiMap<Foo, Bar> bimap = new HashBiMap<Foo, Bar>();

HashBiMap<Foo, Bar> bimap = HashBiMap.create();

与构造函数不同,Guava还充分利用了工厂方法可以拥有有用名称这一事实。考虑ImmutableList.ofImmutableList.copyOfLists.newArrayListWithExpectedSize

它还利用了工厂方法不一定要创建新对象的事实。例如,ImmutableList.copyOf,当给出一个本身为ImmutableList的参数时,将返回该参数而不是进行任何实际复制。

最后,ImmutableList的工厂方法返回ImmutableList的(非公开)子类,例如EmptyImmutableListSingletonImmutableListRegularImmutableList,具体取决于参数

构造函数无法实现这些功能。

答案 7 :(得分:0)

我有一个非常有趣的理由隐藏构造函数检查它,如果有任何其他替代方法可以让我知道

cell.myCustomLabel.attributedText = boldSearchResult(mySearchText, resultString: textForBolding)

答案 8 :(得分:0)

一些主要原因

  • 主要是它为您提供了实例化不同(子)类
  • 的能力
  • 返回null
  • 的可能性
  • 使您可以返回已存在的对象