注意:靜態工廠方法不是設計模式中的工廠方法。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
總之,靜態工廠和構造方法各有優缺點,但一貫在使用構造器以前優先考慮使用靜態工廠。