最近学习了一遍《Effective Java 2》,现在做些记录加深印象。
第1条.考虑用静态工厂方法代替构造器
优势:
1)第一个优势 有名称
对于同一个对象,它的构造函数名字是确定的,有时候你需要基于这个类的自定义对象,采用这种静态构造方法,命名的时候可以很清楚的把这个对象的特点说清楚。
2)第二个优势 不必每次调用都创建一个新的对象
你可以缓存起来,进行重复利用,每次返回的时候都返回同一个对象,如上面的代码所示,静态方法通常会使用预先构建好的实例或者将构建好的实例缓存起来,进行重复利用,从而避免创建不必要的重复对象,比如我们常见的单例模式。
3)第三个优势 可以返回原返回类型的任何子类型对象
适用于基于接口的框架。而且可以使API返回的对象的类是私有的(使用构造函数肯定不行)。
样例:
/**
* 服务注册者接口(注册服务者API)
*/
public interface Privder {
Service getService();
}
/**
* 服务提供接口(服务者)
*/
public interface Service {
}
public class Services {
private Services(){}
//承载服务名称 和服务的 容器
private static final Map<String,Privder> privders= new ConcurrentHashMap<>();
//无定义时 默认此名称
public static final String DEFAULT_P_NAME = "<def>";
/**
* 提供者注册API(默认)
* @param p
*/
public static void registerDefaultPrvider(Privder p){
registerPrvider(DEFAULT_P_NAME,p);
}
/**
* 提供者注册API
* @param name
* @param p
*/
private static void registerPrvider(String name,Privder p) {
privders.put(name,p);
}
/**
* 服务访问API 默认
* @return
*/
public static Service newInstance(){
return newInstance(DEFAULT_P_NAME);
}
/**
* 服务访问API
* @return
*/
private static Service newInstance(String name) {
Privder p = privders.get(name);
if (p == null){
throw new IllegalArgumentException("No privder registered with name:"+ name);
}
return p.getService();
}
}
**
4)第四个优势 在创建参数化类型实例的时候,可以使代码变得更加简洁**
Map<String,List<String>> m = new HashMap<String,List<String>>();
随着类型参数变得越来越长,越来越复杂,这一冗长的说明也很快变得痛苦起来。但是有了静态工厂方法,编译器就可以替你找到类型参数。这被称作类型推导(type inference)。例如,假设HashMap提供了这个静态工厂:
public static <K,V> HashMap<K,V> newInstance(){
return new HashMap<K,V>();
}
你就可以用下面这句简洁的代码代替上面这段繁琐的声明:
Map<String,List<String>> m = HashMap.newInstance();
劣势:
静态工厂方法的主要缺点在于,类如果不含公共的或者受保护的构造器,就不能被子类化。
静态工厂方法的第二个缺点在于,它们与其它的静态方法实际上没有任何区别。