最近开始读《Effective Java》这本书,本文只是对所读过章节的记录以及个人理解与总结,理解不当之处,请见谅。
在Java中,创建新对象的方式一般是通过调用类的构造器方法来完成,然而创建对象的方式也可以通过类静态工厂的方法来完成。 例子如下:
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
通过类静态工厂方法创建对象的方式有以下几个优势:
1.类静态工厂方法可以允许自定义方法名称。
构造器的方法名是固定的,当遇上相同的参数需要构造两种不同的对象时,构造器往往会陷入困境,而类静态工厂方法可以通过不同的方法名清晰地向客户端程序员提供目标对象的信息。
2.在类静态工厂方法中,可以选择返回一个新对象或者已经存在的对象。
构造器方法的使命就是返回一个新对象,而类静态工厂方法则有选择权,文章开始的例子以及单例模式中,类静态工厂方法都是返回一个已存在的对象,而假如在静态工厂方法中直接调用构造器方法则可以直接返回一个新对象。
3.类静态工厂方法可以返回任何其返回类型子类的对象。
构造器方法只能返回当前类的对象,而类的静态工厂方法的返回类型是接口或者抽象类时,该方法就可以返回其返回类型的实现类或者子类的对象。这样做的好处在于API的使用者无需关心具体的实现类。依赖接口而非实现是一种非常好的编程实践。
4.类构造器可以避免重复编写类型。
例如,在构造一个Map对象时:
Map<String, List<String>> m = new HashMap<String,List<String>>();
声明和创建对象时都需要填写具体的类型,用起来非常繁琐。
假如在HashMap中添加这样一个类静态工厂方法:
public static <K,V>HashMap<K,V> newInstance() {
return new HashMap<K,V>();
}
创建新对象时,可以写成:
Map<String,List<String>> m = HashMap.newInstance();
省略了在创建新对象时写类型的必要。实际上,在Java 8中,已经支持在创建新对象时不需要再次填写类型,如下:
Map<String,List<String>> m = new HashMap<>();
所以随着语言的改进,该优势已不再明显。
使用类静态工厂方法创建对象主要有两点劣势:
1.没有public或者protected权限构造器的类不能被继承。
拥有类静态工厂方法的类,为了阻止客户端程序员通过调用构造器创建新对象,通常会将所有构造器的权限置为private,这就导致该类无法被继承,并且客户端程序员必须使用组合而非继承,在某些情境下,这也不是一件坏事。
2.静态工厂方法往往与其他静态方法在JavaDoc中没有区分度。
构造方法在JavaDoc中比静态工厂方法能够更加吸引客户端程序员的注意,解决这个的办法是为静态工厂方法添加注释或者使用以下一些比较通用的静态工厂方法名称。
valueOf -- 类型转换
of -- 同valueOf
getInstance -- 获取一个实例,单例模式中常用此命名
newInstance -- 创建一个新的实例,保证与其他的实例不同
getType -- 同getInstance,只不过是创建一个不同于当前类型的对象
newType -- 同newInstance,只不过是创建一个不同于当前类型的对象
最后,最重要的问题来了,什么情境下采用哪种方式最合适?
其实对于这个问题来说,没有标准的答案,能够充分发挥静态工厂方法创建对象优势,而且能避免构造器劣势的情境下,就该选择使用静态工厂方法;反之,同理。
网友评论