注:本系列对Effective Java各条进行整理和简洁化,经过书籍和网上博客进行整合,主要参考http://www.jianshu.com/u/3b386b0ef996博主的系列。java
首先咱们先看下一个类RandomIntBuilder,用来建立随机的Int整数dom
public class RandomIntBuilder { private final int min; private final int max; public int next() {...} }
接下来咱们来加入几个构造器来看看ui
//没任何问题 public RandomIntBuilder(int min, int max){ this.min = min; this.max = max; } //没任何问题 //产生一个介于min到Integer.MAX_VALUE的值 public RandomIntBuilder(int min){ this.min = min; this.max = Integer.MAX_VALUE; } //编译错误Duplicate method RandomIntBuilder(int) in type RandomIntBuilder //产生一个介于Integer.MIN_VALUE到max的值 public RandomIntBuilder(int max){ this.min = Integer.MIN_VALUE; this.max = max; }
从上面很明显能够看出,由于构造器区别在于参数类型、个数、顺序不一样而已,上面的第三个和第二个构造方法并无这些不一样,所以没法区别才致使报错。这时候,咱们幸亏有静态工厂方法,咱们能够经过使用简单的公共静态方法返回一个类的实例。在Java中,你必定见过Boolean.valueOf吧,就像下面这样:this
public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }
所以,咱们将静态工厂方法用在这里,上面的类就能够变成以下写法:spa
public class RandomIntBuilder { private final int min; private final int max; private RandomIntBuilder (int min, int max) { this.min = min; this.max = max; } public static RandomIntBuilderbetween(int max, int min) { return new RandomIntBuilder (min, max); } public static RandomIntBuilderForMin(int min) { return new RandomIntBuilder (min, Integer.MAX_VALUE); } public static RandomIntBuilderForMax(int max) { return new RandomIntBuilder (Integer.MIN_VALUE, max); } public int next() {...} }
同时,使用静态工厂方法还可让返回对象的类型能够是返回类型的任意子类型。这使你随意更改返回类型而不用担忧影响到客户端代码成为了可能。经过下面的一个例子来讲明。咱们先定义一个接口,这个接口能够产生其余数据类型如String, Double或者Long的随机生成器code
public interface RandomBuilder<T> {
T next();
}
下面咱们来编写下Integer和String的生成器对象
class RandomIntBuilder implements RandomBuilder<Integer> { private final int min; private final int max; RandomIntBuilder (int min, int max) { this.min = min; this.max = max; } public Integer next() {...} }
class RandomStringBuilder implements RandomBuilder<String> { private final String prefix; RandomStringBuilder (String prefix) { this.prefix = prefix; } public String next() {...} }
能够发现,上面的全部的类及类的构造器被定义为包权限。也就是说除了本包以外的客户端代码没法建立这些生成器的实例,那么该怎么办呢?其实咱们只须要提供一个给外面的公共类就能够了blog
public final class RandomBuilderCreator { private RandomBuilderCreator () {} public static final RandomBuilder<Integer> getIntBuilder() { //返回了子类型 return new RandomIntBuilder(Integer.MIN_VALUE, Integer.MAX_VALUE); } public static final RandomBuilder<String> getStringBuilder() { //返回了子类型 return new RandomStringBuilder(""); } }
好了,这就静态工厂方法代替构造器的几点好处了,如今让咱们总结下静态工厂方法和构造器的优劣对比接口
优点:get
①静态工厂方法与构造器不一样的第一大优点在于它们有名称,能更好理解意思。
②静态工厂方法与构造器不一样的第二大优点在于没必要在每次调用它们的时候都建立一个新对象。就像Boolean,咱们不须要建立Boolean对象来获取b的值,而只要调用Boolean.valueOf(b)便可。
③静态工厂方法与构造器不一样的第三大优点在于它们能够返回原返回类型的任意子类型对象。
④静态工厂方法与构造器不一样的第三大优点在于建立参数化实例的时候可使代码变得更加简洁。就像下面的代码
Map<String, List<String>> map = new HashMap<String, List<String>>();
这显得很繁琐,若是HashMap有了如下静态工厂方法,java会进行类型推导,将代码简洁化了为:Map<String, List<String>> map = HashMap.newInstance();
public static <K,V> HashMap<K,V> newInstance(){
return new HashMap<K,V>();
}
劣势:
①静态工厂方法的主要缺点在于类若是不含有公有的或者受保护的构造器,就不能被子类化了。
②静态工厂方法的第二个缺点是他们与其余的静态方法实际上没有任何区别。所以在API中没有像构造方法那样呗明确标识出来,找起来会比较困难繁琐。