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、他们与其他的静态方法没有任何区别

小结:

静态工厂方法和公有构造器都有各自的好处,通常下静态工厂会更加合适。因此急切第一反应就是提供公有构造器,而要先考虑静态工厂是否可以用。

上一篇下一篇

猜你喜欢

热点阅读