
前言
为什么我们要考虑用静态工厂方法替换构造器? 它有什么好处,又有什么不足?本文我们就进行一个简单的介绍,带你领略静态工厂方法的美。
优点
静态工厂方法有名称
因为静态工厂方法有名称,我们可以非常方便的做到见名知义,否则用户只能通过阅读参考文档或者代码才能知道不同的构造器具体有什么不用
不必每次调用都创建一个新对象
Integer tt = new Integer(1);
Integer te = Integer.valueOf(1);
复制代码
我们先看一下上面的两个代码,有什么区别,看起来都是返回了一个Integer,没什么区别,但是内里实际上区别很大
public Integer(int value) {
this.value = value;
}
复制代码
当我们调用构造器的时候每次都是重新创建对象
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
复制代码
而当我们使用valueOf的时候,Java会为在落入IntegerCache中的数字返回相同的对象,这样就避免了创建不必要的重复对象,可以极大地提升性能!但是需要注意的是,这样有可能造成部分基础不熟练的同事使用==对Integer进行判断,当返回结果落入IntegerCache的时候不会有不相等的问题,因为都是同一个对象,但是如果真实环境超过了[-128, 127](127可以通过参数设置),那么这时候可能就会不一样了,会有潜在的bug隐患。
可以返回原返回类型的任何子类型的对象
你可以返回你想返回的任何子类。一种应用是使得API可以返回对象,同时也不会是对象的类变成公有地。用这种方式隐藏实现类会使接口变得非常简洁。
Java 8之前,接口中不能有静态方法,这时候我们都是依靠不可实现类来实现的
Java8之后,我们的接口中可以有静态方法了,所以此时为接口提供不可实现类已经只是因为接口中的静态方法必须是public的。Java 9中静态方法可以是private 的了,但是字段仍然需要是public的。
返回类可随参数而变
每次调用的时候如果我们愿意,是可以通过静态工厂方法的参数值决定返回父类的哪种子类的,构造器就做不到这一点。
java.util.EnumSet 这个就体现了这一点,EnumSet被声明为abstract class类型,EnumSet有两种实现方式,RegularEnumSet和JumboEnumSet,但是这两种实现方式是包私有的,不能在包外访问,因此必须使用工厂方法来创建并返回EnumSet实例,不能通过构造函数来创建。
//noneOf方法
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
复制代码
如果数量小于等于64,我们使用RegularEnumSet,如果大于64时,我们使用JumboEnumSet,使用者无需关心返回的是哪种子类,只要能用就行,甚至我们以后新加子类也对使用者没有影响!这也是为什么我们使用静态工厂来进行创建的原因。 noahsnail.com/2016/09/27/…
返回对象所属的类,在编写包含该静态工厂方法的类时可不存在
这是服务提供者框架的基础,比如JDBC的API就是如此,多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。
缺点
类可能无法子类化
类如果没有public或者protect修饰的构造器,就不能被子类化,不过这样也好,我们最好使用复合而不是继承。
静态工厂方法太不起眼
一眼看过去,静态工厂方法和静态方法没有什么区别的,比如,如果我们想要查明如何实现一个EnumSet,在不搜索的情况下可能会发现直接new不行。对我们查明如何实例化类会有些困难。
作者:临时营地
链接:https://juejin.cn/post/6994696367155183653
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
静态工厂方法相比构造器提供了命名便利、性能优化(如Integer.valueOf()的缓存机制)、返回任意子类对象的能力,以及在服务提供者框架中的应用。然而,它可能导致类无法被子类化,并且其不起眼的特性可能使实例化过程难以查找。文章通过代码示例阐述了这些优缺点,强调在设计API时考虑使用静态工厂方法的理由。

被折叠的 条评论
为什么被折叠?



