考虑用静态工厂方法替代构造器
对于类而言,为了让客户端获得它自身的一个实例,最常用的方法就是提供一个 公有
的构造器,除了这种方式外,另外一种实现方式 是为类提供一个公有的的静态工厂方法
静态工厂方法的优势
公有构造器的方式的缺点
- 只能通过
new className()
的方式来实现 - 每次调用必然返回一个新的对象
- 返回类型就是该类
使用静态工厂方法的优势
- 静态工厂方法是有名称的
它可以描述返回对象的特点,一个类如果需要多个带有相同前面的构造器时,就用静态工厂方法来代替构造器,使用不同的方法名称以突出他们的区别比如BigInteger.probalePrime()
这个静态工厂方法描述了返回的实例对象是一个素数。 - 不必在每次调用它们的时候都创建一个新的对象
对于一些创建代价比较大又可以重复利用的对象,我们可以预先创建好对象实例,或者将构建好的实例缓存起来,重复利用,每次调用工厂方法时返回相同的对象。 - 可以返回原返回类型的任何子类型
考虑到一些私有的类我们不想对外界暴露,又要提供获得该类对象的方法,采用静态工厂方法的方式可以让用户致电,被返回的对象是由相关接口精确确定的,对于返回对象的具体确定的类的存在对于客户端来说是不可见的。
静态工厂方法返回的对象所属的类,在编写保护该静态工厂方法的类时可以不必存在。
这种灵活的静态工厂方法构成了服务提供者框架(Service Provider Framwork)的基础,例如 JDBC(Java数据库连接) API,服务提供者框架是指这样一个系统;多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。 - 在创建参数化类型实例的时候,它们使代码变得更加简洁
在调用参数化类的构造器时,即使类型参数很明显,也必须指明,这通常要求你接连两次提供类型参数
Map<String,List<String>> m = new HashMap<String,List<String>>
,这个代码太冗长,使用静态工厂方法,编译器就可以替你找到类型参数。
public static <k,v> HashMap<k,v> newInstance(){
return new HashMap<k,v>();
}
用下面这句代码替代之前繁琐的申明
Map<String,List<String>> m = HashMap.newInstance();
在我用Android Studio 的时候,Java 1.7 的时候,已经不需要申明两次泛型类型了,可以直接这样
Map<String,List<String>> m = new HashMap<>
所以这点上,你可以用这种方式只是拥有之前说的第二种优势
总结
静态工厂方法和公有构造器都各有用处,我们需要理解它们各自的长处。静态工厂通常更有用处,优先考虑静态工厂方法。静态工厂方法的缺点
- 静态工厂方法的主要缺点在于,类如果不含有公有的或者受保护的构造器,就不能被子类化
不过这也鼓励你使用复合(composition)来扩展类,而不是继承 - 与其他静态方法实际上没有区别
你无法向构造器那样在API文档中明确的标示出来这份方法是为了创建类实例的,不过你可以在类或者接口注释中关注静态工厂,并遵守标准的命名习惯,这可以弥补这一劣势
静态工厂方法的一些惯用名称
- value of 实际上是类型转换方法
- of valueof的一种简洁提地啊
- getInstance 返回的实例是通过方法的参数来描述的
- newInstanc new字样,你需要保证额每个实例都与所有其他实例不同,即每次都是创建一个实例,保证没有复用
- getType 与 getInstance 一样,但是在工厂方法处于不同的类中的时候使用。Type 表示工厂方法返回的对象类型
- newType 同上,new字样,实现上需要保证是个新的实例