Effective Java学习笔记 (一)考略使用静态工厂方法
2018-08-12 本文已影响92人
猪_队友
优势:
1、 他们有名称
通过名称可以更清楚的知道这个方法的作用。
比如ImageLoader.loadIconImage(String url); 和 ImageLoader(String url,String type)、ImageLoader(String url)
用户永远记不住参数类型顺序上的有所不同,也记不住应该用哪一个构造器,所以会常常调用错误构造器。所以静态工厂方法有名称,可以不受这个的影响。
2、不必每次调用他们的时候都创建一个新的对象
这个可以使不可变类可以使用预先构件好的实例。进行重复使用。参考单例模式。
3、他们可以返回原返回类型的任何子类型的对象
这样可以让我们在选择对象的类的时候有了更大的灵活性。
这种灵活性的一种应用是:API可以返回对象,同时又不会使对象的类变成共有的。以这样的方式隐藏实现类会使API变得非常简单。
下面是一个简单的实现,包含一个服务提供者接口和一个默认提供者
//服务接口
public interface Service{
}
//服务提供者接口
public interface Provider{
//这个方法提供服务
Service newService();
}
public class Service{
//私有构造方法
private Service(){}
//用来存放不同的服务提供者 根据名字区分
private static final Map<String,Provider> providers =
new ConcurrentHashMap<String,Providers>();
//默认的服务提供者的名字
public static final String DEFAULT_PROVIDER_NAME = "<def>";
//默认注册 默认名称的服务提供者
public static void registerDefaultProvider(Provider p){
registerProvider(DEFAULT_PROVIDER_NAME,p);
}
//把自己创建名称的服务提供者加入这个Map里
public static void registerDefaultProvider(String name,Provider p){
providers.put(name,p);
}
public static Service newInstance(){
return newInstance(DEFAULT_PROVIDER_NAME);
}
public static Service newInstance(String name){
Provider p = providers.get(name);
if(p==null){
throw new IllegalArgumentException("No provider registered with name"+name);
}
return p.newService();
}
}
这个是我们常见的服务提供者控件的简化版本。
我们可以看到通过我们不同的静态工厂方法,使构造方法私有,隐藏了实现类,只需要实现类实现这个接口就可以了,比如这个Provider,对于实现类我们是不可预料的,所以大大增加了灵活性。
4、再创建参数化类型实例的时候,他们使代码变得更加简洁
比如这个:
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();
这样是不是很爽啊。代替了繁琐的声明。
缺点:
1、类如果不含共有的或者受保护的构造器,就不能被子类化
对于共有的静态工厂所返回的非共有类也是如此。
例如:要想将Collections FrameWork中的任何方便的实现类子类化,这是不可能的。但是也因祸得福,鼓励程序员使用复合(composition),而不是继承。
2、他们与其他的静态方法没有任何区别
小结:
静态工厂方法和公有构造器都有各自的好处,通常下静态工厂会更加合适。因此急切第一反应就是提供公有构造器,而要先考虑静态工厂是否可以用。