注意:静态工厂方法不是设计模式中的工厂方法。java
一个类向客户端提供静态工厂方法有以下好处:程序员
由静态工厂方法返回的对象的类甚至没必要在编写静态工厂方法所在的类时就存在。静态工厂的这种灵活性是服务提供者框架(service provider framework)的基石,例如JDBC。服务提供者框架是一个系统,在这个系统中,服务提供者实现服务,这个系统让这些实现对客户端可用,从而把客户端与实现分离。设计模式
服务提供者框架有三个基本的组件:由提供者实现的服务接口、系统用于注册服务实现并让其对客户端可用的提供者注册API、客户端用于获取服务实现的服务访问API。服务访问API一般容许让客户端指定某些条件以便选择一个提供者,但客户端不是必需要指定,若是没有指定,API会返回一个默认实现。服务访问API就是构成服务提供者框架的基石的灵活静态工厂。数组
服务提供者接口有一个可选的组件:服务提供者接口,由提供者用于建立他们本身的服务实现的实例。在没有服务提供者接口的状况下,实现是经过类名进行注册,并经过反射进行实例化。在JDBC中,Connection就是服务接口,DriverManager.registerDriver()就是服务提供者注册接口,DriverManager.getConnection()是服务访问接口,Driver是服务提供者接口。缓存
如今有许多服务提供者框架模式的变种,例如,经过使用适配器,服务访问API能够返回比提供者所须要的服务接口更加丰富的服务接口,下面是一个服务提供者接口及其一个默认实现:框架
// Service provider framework sketch
// Service interface
public interface Service {
... // Service-specific methods go here
}
// Service provider interface
public interface Provider {
Service newService();
}
// Noninstantiable class for service registration and access
public class Services {
private Services() { } // Prevents instantiation (Item 4)
// Maps service names to services
private static final Map<String, Provider> providers =
new ConcurrentHashMap<String, Provider>();
public static final String DEFAULT_PROVIDER_NAME = "<def>";
// Provider registration API
public static void registerDefaultProvider(Provider p) {
registerProvider(DEFAULT_PROVIDER_NAME, p);
}
public static void registerProvider(String name, Provider p){
providers.put(name, p);
}
// Service access API
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();
}
} ide
没有使用静态工厂时:工具
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();
遗憾的是,标准的集合类实现中,例如HashMap并无相似上面定义的工厂方法。但能够把这种方法放到本身的工具类中,更加剧要的是,能够在本身的参数化类中提供这种静态工厂方法。
只提供静态工厂方法的类的主要缺点在于不能被子类化,由于没有public或protected的构造器的类是不能被子类化的。
由public权限的静态工厂返回的非public类也是不能被子类化的,例如,不能子类化Collections里面的实现类,这能够说是塞翁失马,所以这样能够促进程序员使用组合而不是继承。
另外一个缺点在于静态工厂方法不易与其它静态方法区分开。
主要是由于静态工厂方法不像构造器那样明显地出如今API文档中,所以很难知道如何使用类中提供的静态工厂来代替构造方法实例化对象。能够经过在类或接口中写注释来讲明,而且让静态工厂方法名遵循约定:
valueOf、of、getInstance、newInstance、getType、newType
总之,静态工厂和构造方法各有优缺点,但一贯在使用构造器以前优先考虑使用静态工厂。