[英]What are static factory methods?
什么是“靜態工廠”方法?
靜態工廠方法模式<\/a>是一種封裝對象創建的方法。 如果沒有工廠方法,您只需直接調用類的
構造函數<\/a>:
Foo x = new Foo()<\/code> 。
使用這種模式,您將改為調用工廠方法:
Foo x = Foo.create()<\/code> 。
構造函數被標記為私有,因此只能從類內部調用它們,而工廠方法被標記為
static<\/code><\/a> ,因此可以在沒有對象的情況下調用它。
這種模式有幾個優點。 一是工廠可以從許多子類(或接口的實現者)中選擇並返回。 這樣,調用者可以通過參數指定所需的行為,而不必知道或理解潛在的復雜類層次結構。
正如 Matthew 和 James 所指出的,另一個優勢是控制對有限資源(例如連接)的訪問。
這是一種實現可重用對象池的<\/a>方法——而不是構建、使用和拆除對象,如果構建和銷毀是昂貴的過程,那么構建一次並回收它們可能更有意義。
工廠方法可以返回一個現有的、未使用的實例化對象,如果它有一個,或者如果對象計數低於某個下限閾值,則構造一個,或者如果它高於上限閾值,則拋出異常或返回
null<\/code> 。
根據 Wikipedia 上的文章,多個工廠方法還允許對類似參數類型進行不同的解釋。
通常構造函數與類具有相同的名稱,這意味着您只能擁有一個具有給定簽名<\/a>的構造函數。 工廠不受限制,這意味着您可以有兩種不同的方法來接受相同的參數類型:
Coordinate c = Coordinate.createFromCartesian(double x, double y)
筆記! “靜態工廠方法<\/strong>與工廠<\/strong>方法<\/strong>模式不同” (c) Effective Java,Joshua Bloch。
工廠方法:“定義一個用於創建對象的接口,但讓實現該接口的類決定實例化哪個類。工廠方法讓一個類將實例化推遲到子類”(c)GoF。
“靜態工廠方法只是一個返回類實例的靜態方法。” (c) 有效的 Java,Joshua Bloch。 通常這個方法在一個特定的類中。
區別:
靜態工廠方法的關鍵思想是控制對象的創建並將其從構造函數委托給靜態方法。 要創建的對象的決定就像在抽象工廠中在方法之外做出的一樣(在常見情況下,但並非總是如此)。 而工廠方法的關鍵(!)思想是委托決定在工廠方法中創建什么類的實例。 例如,經典的 Singleton 實現是靜態工廠方法的一個特例。 常用的靜態工廠方法示例:
我們避免提供對數據庫連接的直接訪問,因為它們是資源密集型的。 所以我們使用靜態工廠方法
getDbConnection<\/code> ,如果我們低於限制,它會創建一個連接。
否則,它會嘗試提供“備用”連接,如果沒有則失敗並出現異常。
public class DbConnection{
private static final int MAX_CONNS = 100;
private static int totalConnections = 0;
private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();
private DbConnection(){
// ...
totalConnections++;
}
public static DbConnection getDbConnection(){
if(totalConnections < MAX_CONNS){
return new DbConnection();
}else if(availableConnections.size() > 0){
DbConnection dbc = availableConnections.iterator().next();
availableConnections.remove(dbc);
return dbc;
}else {
throw new NoDbConnections();
}
}
public static void returnDbConnection(DbConnection dbc){
availableConnections.add(dbc);
//...
}
}
靜態工廠方法可以提高可讀性:
比較
public class Foo{
public Foo(boolean withBar){
//...
}
}
//...
// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.
到
public class Foo{
public static Foo createWithBar(){
//...
}
public static Foo createWithoutBar(){
//...
}
}
// ...
// This is much easier to read!
Foo foo = Foo.createWithBar();
- 有名字,不像構造函數,可以澄清代碼。<\/li>
- 無需在每次調用時創建新對象 - 如有必要,可以緩存和重用對象。<\/li>
- 可以返回其返回類型的子類型 - 特別是,可以返回調用者不知道其實現類的對象。 這是許多使用接口作為靜態工廠方法的返回類型的框架中非常有價值且廣泛使用的特性。<\/li><\/ul><\/blockquote>
來自http:\/\/www.javapractices.com\/topic\/TopicAction.do?Id=21<\/a>
"
這一切都歸結為可維護性。 最好的表達方式是,每當您使用
new<\/code>關鍵字創建對象時,您就是在將您正在編寫的代碼耦合到實現中。
工廠模式允許您將創建對象的方式與使用對象的方式分開。 當您使用構造函數創建所有對象時,您實際上是將使用該對象的代碼硬連接到該實現。 使用您的對象的代碼“依賴於”該對象。 從表面上看,這似乎沒什么大不了的,但是當對象發生更改時(考慮更改構造函數的簽名,或對對象進行子類化),您必須返回並在各處重新連接。
今天,工廠在很大程度上被擱置在使用依賴注入的支持下,因為它們需要大量的樣板代碼,結果證明自己有點難以維護。 依賴注入基本上等同於工廠,但允許您指定對象如何以聲明方式連接在一起(通過配置或注釋)。
如果一個類的構造函數是私有的,那么你不能從它的外部為類創建一個對象。
class Test{
int x, y;
private Test(){
.......
.......
}
}
我想我會在這篇文章中添加一些關於我所知道的內容。 我們在recent android project
中廣泛使用了這種技術。 除了creating objects using new operator
您還可以使用static method
來實例化一個類。 代碼清單:
//instantiating a class using constructor
Vinoth vin = new Vinoth();
//instantiating the class using static method
Class Vinoth{
private Vinoth(){
}
// factory method to instantiate the class
public static Vinoth getInstance(){
if(someCondition)
return new Vinoth();
}
}
靜態方法支持條件對象創建:每次調用構造函數時都會創建一個對象,但您可能不希望這樣。 假設您只想檢查某些條件,然后才想創建一個新對象。除非滿足您的條件,否則您不會每次都創建 Vinoth 的新實例。
另一個來自Effective Java的例子。
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
此方法將布爾原始值轉換為布爾對象引用。 Boolean.valueOf(boolean)
方法說明了我們,它從不創建對象。 static factory methods
從重復invocations
返回相同對象的能力允許類在任何時候保持對存在的實例的嚴格控制。
Static factory methods
與constructors
不同,它們可以返回其返回類型的任何子subtype
的object
。 這種靈活性的一個應用是 API 可以返回對象而無需公開它們的類。 以這種方式隱藏實現類會導致 API 非常緊湊。
Calendar.getInstance() 是上面的一個很好的例子,它根據語言環境創建一個BuddhistCalendar
日歷, JapaneseImperialCalendar
帝國日歷或默認一個Georgian
。
我能想到的另一個例子是Singleton pattern
,您可以在其中將構造函數設為私有,創建一個自己的getInstance
方法,您可以確保始終只有一個實例可用。
public class Singleton{
//initailzed during class loading
private static final Singleton INSTANCE = new Singleton();
//to prevent creating another instance of Singleton
private Singleton(){}
public static Singleton getSingleton(){
return INSTANCE;
}
}
源自靜態工廠的優點之一是 API 可以返回對象而無需公開其類。 這導致非常緊湊的 API。 在 java 中,這是通過 Collections 類實現的,該類隱藏了大約 32 個類,這使得它的集合 API 非常緊湊。
工廠方法是一種抽象對象實例化的方法。 通常,當您知道需要實現某個接口但不知道實現類的類的新實例時,工廠很有用。
這在處理相關類的層次結構時很有用,一個很好的例子就是 GUI 工具包。 您可以簡單地對構造函數的調用進行硬編碼,以實現每個小部件的具體實現,但是如果您想將一個工具包換成另一個工具包,那么您將有很多地方需要更改。 通過使用工廠,您可以減少需要更改的代碼量。
具有私有構造函數的靜態工廠方法的優點之一(必須限制外部類的對象創建以確保不會在外部創建實例)是您可以創建實例控制的<\/em>類。 並且實例控制的類保證在程序運行期間不存在兩個相等的不同實例( a.equals(b) 當且僅當 a==b<\/strong> ),這意味着您可以使用==<\/strong>運算符而不是equals<\/strong>方法檢查對象的相等性,根據有效的java。
靜態工廠方法從重復調用返回相同對象的能力允許類在任何時候保持對存在的實例的嚴格控制。 執行此操作的類被稱為實例控制的。 編寫實例控制類有幾個原因。 實例控制允許一個類保證它是單例(第 3 項)或不可實例化(第 4 項)。 此外,它允許不可變類(第 15 條)保證不存在兩個相等的實例:a.equals(b) 當且僅當 a==b 時。 如果一個類做出了這種保證,那么它的客戶端可以使用 == 運算符而不是 equals(Object) 方法,這可能會提高性能。 枚舉類型(第 30 項)提供了這種保證。
來自 Effective Java,Joshua Bloch(第 1 項,第 6 頁)
Java 實現包含實用程序類java.util.Arrays和java.util.Collections它們都包含靜態工廠方法、它的示例以及如何使用:
Arrays.asList("1","2","3")
Collections.synchronizedList(..), Collections.emptyList(), Collections.unmodifiableList(...)
(只有一些例子,可以檢查 javadocs 的 mor 方法例子https://docs.oracle.com/javase/8/docs/ api/java/util/Collections.html )
java.lang.String類也有這樣的靜態工廠方法:
String.format(...), String.valueOf(..), String.copyValueOf(...)
當您想確保只有一個實例將返回要使用的具體類時,靜態工廠方法是很好的選擇。
例如,在一個數據庫連接類中,您可能希望只有一個類創建數據庫連接,這樣如果您決定從 Mysql 切換到 Oracle,您只需更改一個類中的邏輯,應用程序的其余部分將使用新連接。
如果你想實現數據庫池,那么也可以在不影響應用程序的其余部分的情況下完成。
它保護應用程序的其余部分免受您可能對工廠進行的更改,這就是目的。
它是靜態的原因是如果你想跟蹤一些有限的資源(套接字連接或文件句柄的數量),那么這個類可以跟蹤有多少已經被傳遞和返回,所以你不會用盡資源有限。
靜止的
<\/blockquote>使用關鍵字“static”聲明的成員。
工廠方法
創建和返回新對象的方法。
在爪哇
編程語言與“靜態”的含義有關,但與“工廠”的定義無關。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.