考慮使用靜态工廠方法替代構造方法
1. 建立對象
什麼是靜态工廠方法
在 Java 中,獲得一個類執行個體最簡單的方法就是使用 new 關鍵字,通過構造函數來實作對象的建立。
eg:
Dog dog=new Dog();
Date date=new Date();
而靜态工廠方法:
Calendar calendar = Calendar.getInstance();
Integer number = Integer.valueOf("3");
像這樣,不通過new關鍵字,通過一個靜态方法得到類的實列的方法就是靜态工廠方法。
2. 靜态工廠方法和執行個體工廠方法和工廠模式
靜态工廠方法:
就是直接可以通過靜态方法來執行個體化一個對象
public class Car{
public static Car newtInstance(){
return new Car();
}
}
Car .newtInstance();
建立 Car對象直接調用Car類的靜态方法newtInstance方法來進行實作
執行個體工廠方法:
就是先建立類對象,然後通過對象來調用建立執行個體對象的方法
public class CarFactory {
public Car newtInstance(){
return new Car();
}
}
CarFactory carFactory =new CarFactory();
carFactory.newtInstance();
工廠模式
靜态工廠方法通常指的是某個類裡的靜态方法,通過調用該靜态方法可以得到屬于該類的一個執行個體;
工廠模式是一種設計模式。具體看設計模式。
如果要說相似的話,靜态工廠方法跟簡單工廠模式倒有那麼點像,不過差別也挺大,簡單工廠模式裡的靜态工廠方法會建立各種不同的對象(不同類的執行個體),而靜态工廠方法一般隻建立屬于該類的一個執行個體(包括子類);
3. 使用靜态工廠方法的優點
1.有名字,可讀性更強
由于語言的特性,Java 的構造函數都是跟類名一樣的。這導緻的一個問題是構造函數的名稱不夠靈活,經常不能準确地描述傳回值,在有多個重載的構造函數時尤甚,如果參數類型、數目又比較相似的話,那更是很容易出錯。
eg:
Date date2 = new Date("0");
Date date3 = new Date(1,2,1);
Date 類有很多重載函數,我們發現,可讀性差,不查文檔,不看注釋很難知道其建立的對象的具體含義
2.與構造方法不同,它們不需要每次調用時都建立一個新對象
JDK中的Boolean類的valueOf方法可以很好的印證這個優勢,在Boolean類中,有兩個事先建立好的Boolean對象(True,False)
public final class Boolean implements java.io.Serializable,
Comparable<Boolean>
{
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code true}.
*/
public static final Boolean TRUE = new Boolean(true);
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code false}.
*/
public static final Boolean FALSE = new Boolean(false);
當我們調用Boolean.valueOf(“true”)方法時,傳回的就是這兩個執行個體的引用,這樣可以避免建立不必要的對象,如果使用構造器的話,就達不到這種效果了;
public static Boolean valueOf(String s) {
return toBoolean(s) ? TRUE : FALSE;
}
3.可以傳回其傳回類型的任何子類型的對象
Class Person {
public static Person getInstance(){
return new Person();
// 這裡可以改為 return new Player() / Cooker()
}
}
Class Player extends Person{
}
Class Cooker extends Person{
}
public static Person getPlayer(){
return new Player ();//或者return new Cooker();
}
4.在建立帶泛型的執行個體時,能使代碼變得簡潔
這條主要是針對帶泛型類的繁瑣聲明而說的,需要重複書寫兩次泛型參數:
class MyMap<K,V> {
/**
*
*/
public MyMap()
{
}
public static <K,V> MyMap<K,V> newInstance(){
return new MyMap<K, V>();
}
}
MyMap<String, String> map1 = new MyMap<String, String>();
//更加簡潔,不需要重複指明類型參數,可以自行推導出來
MyMap<String, String> map2 = MyMap.newInstance();
不過自從 java7 開始,這種方式已經被優化過了 —— 對于一個已知類型的變量進行指派時,由于泛型參數是可以被推導出,是以可以在建立執行個體時省略掉泛型參數。
Map<String,Date> map = new HashMap<>();
4. 使用靜态工廠方法的缺點
1.如果類不含public或protect的構造方法,将不能被繼承
如下類,不能被其它類繼承
class MyMap<K,V> {
private MyMap()
{
}
public static <K,V> MyMap<K,V> newInstance(){
return new MyMap<K, V>();
}
}
2.與其它普通靜态方法沒有差別,沒有明确的辨別一個靜态方法用于執行個體化類
是以,一般一個靜态工廠方法需要有詳細的注釋,遵守标準的命名,如使用getInstance、valueOf、newInstance等方法名;
下面是一些靜态工廠方法的常用名稱。以下清單并非完整:
-
from——A 類型轉換方法,它接受單個參數并傳回此類型的相應執行個體,例如:Date d = Date.from(instant);
of——一個聚合方法,接受多個參數并傳回該類型的執行個體,并把他們合并在一起,例如:Set faceCards = EnumSet.of(JACK, QUEEN, KING);
-
valueOf——from 和 to 更為詳細的替代 方式,例如:BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
instance 或 getinstance——傳回一個由其參數 (如果有的話) 描述的執行個體,但不能說它具有相同的值,例如:StackWalker luke = StackWalker.getInstance(options);
- create 或 newInstance——與 instance 或 getInstance 類似,除了該方法保證每個調用傳回一個新的執行個體,例如:Object newArray = Array.newInstance(classObject, arrayLen);
- getType——與 getInstance 類似,但是如果在工廠方法中不同的類中使用。Type 是工廠方法傳回的對象類型,例如:FileStore fs = Files.getFileStore(path);
- newType——與 newInstance 類似,但是如果在工廠方法中不同的類中使用。Type 是工廠方法傳回的對象類型,例如:BufferedReader br = Files.newBufferedReader(path);
- type—— getType 和 newType 簡潔的替代方式,例如:List litany = Collections.list(legacyLitany);\
總之,靜态工廠方法和公共構造方法都有它們的用途,并且了解它們的相對優點是值得的。通常,靜态工廠更可取,是以避免在沒有考慮靜态工廠的情況下提供公共構造方法。
本文是根據Effctive java和網上部分部落格總結而出。 侵删。