考慮用靜态工廠方法替代構造器
考慮使用靜态工廠方法來替代構造器的原因:
- 靜态工廠方法有名稱:普通的構造器中,參數并不能很好地描述傳回對象的特點,代碼的閱讀性不好。
考慮下面的程式:
Random random = new Random();
BigInteger integer = BigInteger.probablePrime(3, random);
該代碼的含義是傳回一個很有可能是質數并且長度為3的BigInteger對像,這裡的長度隻的是将整數裝換成二進制後的長度;很有可能指的是:不是質數的機率不超過2-100。
但是如果使用的是構造函數:BigInteger(int, Random),則很難通過參數來猜測傳回的是什麼東西。
2. 使用靜态工廠方法不需要每次調用的時候都建立一個新的對象。
如果一些不可變類在使用之前就已經建立好了執行個體,或者将建構好的執行個體緩存起來的話,那麼在實際使用的時候就能過直接拿過來用,避免了建立不必要的重複對象,下面還是通過已經實際應用的例子來看一下:
|
這行代碼的含義就是建立一個值為true的Boolean對象,我們看一下它的源碼:
1 2 3 | |
而TRUE和FALSE的定義如下:
1 2 3 | |
很明顯,這兩個被直接定義成了不可變類,可以重複使用。如果某些服務裡面需要經常建立相同的對象,并且建立對象的代價比較高,則使用這種方法可以顯著提高性能。
3. 使用靜态工廠方法可以傳回原傳回類型的任何子類型的對象。
如果API可以傳回對象,但同時又不會是對象的類變成公有的,這種方法隐藏了實作類,同時也使API變得簡潔。
要說具體執行個體的話,Java Collections Framework的集合接口中,幾乎所有的實作都是通過一個靜态工廠方法在一個不可執行個體化的類中導出。
網絡盜圖:

服務提供者架構(Service Provider Framework)
作者提到:靜态工廠方法傳回的對象所屬的類,在編寫該靜态工廠方法的類時可以不必存在。就是多個服務提供者實作一個服務,系統為服務提供者的用戶端提供多個實作,并把他們從多個實作中解耦出來。
服務提供者架構元件:服務接口(Service Interface)、提供者注冊API(Provider Registration API)、服務通路API(Service Access API)以及可選元件 服務提供者接口(Service Provider Interface)。
感覺略難懂啊。。。biubiu~
對于JDBC:Connection是服務接口;DriverManager.RegisterDriver就是提供者注冊API;DriverManager.getConnection就是服務通路API;Driver就是服務提供者接口。
(PS:是不是吧JDBC的東西忘了?還能手寫出來不?趕緊拿出小本本記下來。。。)
public static void main(String[] args) throws ClassNotFoundException, SQLException {
String URL = "jdbc:mysql://127.0.0.1:3306/study?useUnicode=true&characterEncoding=utf-8";
String USER = "root";//使用者名
String PASSWORD = "xxxxx";//你的MySQL密碼
//1.加載驅動程式
Class.forName("com.mysql.jdbc.Driver");
//2.獲得資料庫連結
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
//3.通過資料庫的連接配接操作資料庫,實作增删改查(使用Statement類)
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("select * from user");
//4.處理資料庫的傳回結果(使用ResultSet類)
while (rs.next()) {
System.out.println(rs.getString("username") + " " + rs.getInt("age"));
}
//關閉資源
rs.close();
st.close();
conn.close();
}
稍微有點不太規範哈,不過功能是可以實作的。其中,如果使用了Maven來管理項目的話,需要添加:
1 2 3 4 5 6 | |
下面還有一個具體的模闆可供參考,以後可以直接拿過去稍微修改一下就可以用了,完美~:
//這是服務接口 Service Interface
public interface Service {
//各種方法
}
//這是服務提供者接口 Service Provider Interface
public interface Provider {
Service newService();
}
//這是一個不能直接執行個體化的類用來進行注冊和通路的
public class Services {
private Services() { //禁止執行個體化
}
private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
public static final String DEAFULT_PROVIDER_NAME = "default";
//提供着注冊API Provider Registration API
public static void registerDefaultProvider(Provider provider) {
registerProvider(DEAFULT_PROVIDER_NAME, provider);
}
public static void registerProvider(String name, Provider provider) {
providers.put(name, provider);
}
//服務通路API Service Access API
public static Service newInstance() {
return newInstance(DEAFULT_PROVIDER_NAME);
}
public static Service newInstance(String name) {
Provider provider = providers.get(name);
if (null == provider) {
throw new IllegalArgumentException("No Provider registered with name" + name);
}
return provider.newService();
}
}
缺點
任何方法或多或少都會優缺點,沒有最好的方法,隻有最合适的方法,對一個新的方法要全面了解其優缺點,然後根據自己的實際情況,選擇一個最合适的方法。
1、類如果不含公有的或者受保護的構造器的話,就不能夠被子類化,沒毛病啊~
2、其實靜态工廠方法跟其他靜态方法實際上沒啥差別,畢竟實作方法是類似的嘛~
靜态工廠方法常用的名稱,含義也比較直白:
- valueOf:一般來說傳回的執行個體跟參數有相同的值。
- of:比valueOf更簡潔,含義類似。
- getInstance:傳回一個具體的執行個體,可以指定參數進行具體化差別。如果是單例(Singleton)的話,無參數,都傳回唯一的執行個體。
- getType: 字面意思,傳回對象類型,so easy。
參考:Effective Java 中文版(第二版)