1.優(yōu)先使用靜態(tài)工廠方法代替構(gòu)造方法-[創(chuàng)建和銷毀對象]

在之前創(chuàng)建一個類對外提供對象實例的方法是提供一個構(gòu)造方法, 還有另一種方式, 那就是提供一個公共的靜態(tài)方法, 這個方法只是用于返回其所在類的實例, 下面是一個Boolean類的一個簡單的例子(Boolean基本類型的包裝類)。

// 此方法將`boolean`基本類型轉(zhuǎn)換為`Boolean`對象引用
public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

從上面的代碼片段可以看到, 對外提供一個用于創(chuàng)建本類實例的靜態(tài)方法, 在方法內(nèi)部創(chuàng)建實例, 這樣可以讓調(diào)用者無需知道類的創(chuàng)建細(xì)節(jié), 只需調(diào)用方法即可, 當(dāng)然, 使用靜態(tài)方法構(gòu)建實例并不是十全十美的, 既有優(yōu)點, 同時也有缺點

優(yōu)點

1.靜態(tài)工廠方法更能直觀的描述創(chuàng)建對象, 方便閱讀

因為在Java中構(gòu)造方法必須跟類名一致, 也就導(dǎo)致了這個構(gòu)造方法并不能很好地描述被返回的對象,但是使用靜態(tài)工廠方法本身可以命名更易于使用, 可以更容易直觀描述被創(chuàng)建的對象。
例如,User類有一個newUserWithGenderMale()的靜態(tài)工廠方法用于返回性別為男的User對象, 如果是比較復(fù)雜的對象,使用靜態(tài)工廠方法生成的方法可以使調(diào)用者更容易閱讀

2.不必每次調(diào)用時都創(chuàng)建對象,節(jié)省內(nèi)存開銷, 類似于Flyweight(享元)設(shè)計模式

使用構(gòu)造方法會每次創(chuàng)建都會返回一個對象, 如果在構(gòu)造比較重量級的對象的話, 每次構(gòu)造的成本比較大。
如果使用靜態(tài)工廠的話, 如果該類有復(fù)用的需求的話, 可以將這個類緩存起來, 便于下一次使用, 更節(jié)省內(nèi)存。
例如, Boolean.valueof(boolean)方法說明了這種方法:它從不創(chuàng)建對象。
同時,它允許一個不可變的值類保證不存在兩個相同的實例:當(dāng)且僅當(dāng)a == ba.equals(b)。

3.它可以返回其返回類型的任何子類對象, 因為構(gòu)造方法在調(diào)用時就確定了類型

在Java 8之前,接口不能有靜態(tài)方法。根據(jù)約定,一個名為Type的接口的靜態(tài)工廠方法被放入一個非實例化的伙伴類(companion class)Types類中。例如,Java集合框架有45個接口的實用工具實現(xiàn),提供不可修改的集合、同步集合等等。
幾乎所有這些實現(xiàn)都是通過靜態(tài)工廠方法在一個非實例類(java.util.Collections)中導(dǎo)出的。返回對象的類都是非公開的。
Collections框架API的規(guī)模要比它之前輸出的45個單獨的公共類要小得多,每個類有個便利類的實現(xiàn)。不僅是API的大部分減少了,還包括概念上的權(quán)重:程序員必須掌握的概念的數(shù)量和難度,才能使用API。
從Java 8開始,接口不能包含靜態(tài)方法的限制被取消了,所以通常沒有理由為接口提供一個不可實例化的伴隨類。 很多公開的靜態(tài)成員應(yīng)該放在這個接口本身。 但是,請注意,將這些靜態(tài)方法的大部分實現(xiàn)代碼放在單獨的包私有類中仍然是必要的。 這是因為Java 8要求所有接口的靜態(tài)成員都是公共的。 Java 9允許私有靜態(tài)方法,但靜態(tài)字段和靜態(tài)成員類仍然需要公開。

4.可以根據(jù)傳入?yún)?shù)的不同而返回不同實例

EnumSet類沒有公共構(gòu)造方法,只有靜態(tài)工廠。 在OpenJDK實現(xiàn)中,它們根據(jù)底層枚舉類型的大小返回兩個子類中的一個的實例:如果大多數(shù)枚舉類型具有64個或更少的元素,靜態(tài)工廠將返回一個RegularEnumSet實例, 返回一個long類型;如果枚舉類型具有六十五個或更多元素,則工廠將返回一個JumboEnumSet實例,返回一個long類型的數(shù)組。
這兩個實現(xiàn)類的存在對于客戶是不可見的。 如果RegularEnumSet不再為小枚舉類型提供性能優(yōu)勢,則可以在未來版本中將其淘汰,而不會產(chǎn)生任何不良影響。 同樣,未來的版本可能會添加EnumSet的第三個或第四個實現(xiàn),如果它證明有利于性能。 客戶既不知道也不關(guān)心他們從工廠返回的對象的類別; 他們只關(guān)心它是EnumSet的一些子類。

5.構(gòu)成基于接口的框架

JDBC中, Java對數(shù)據(jù)庫廠商提供了一些數(shù)據(jù)庫操作接口例如Connection, Driver, Statement。
而數(shù)據(jù)庫廠商只需要實現(xiàn)這些接口就可以完成對其數(shù)據(jù)庫的操作。
這樣設(shè)計的好處是用戶只需要知道其接口方法用來干什么的, 并不需要關(guān)注其內(nèi)部原理和實現(xiàn)細(xì)節(jié), 在需要對應(yīng)的數(shù)據(jù)庫廠商的Driver時加載對應(yīng)的Driver類。
例如以前在JDBC中注冊MySQL的Driver只需要通過Class.forName("com.mysql.jdbc.Driver"), 注冊對應(yīng)的Driver類, 而在這個類被加載的時候會觸發(fā)靜態(tài)代碼塊如下

static {
    try {
        DriverManager.registerDriver(new Driver());
    } catch (SQLException var1) {
        throw new RuntimeException("Can't register driver!");
    }
}

DriverManager.registerDriver(new Driver());這個方法是Java對于各個數(shù)據(jù)庫廠商提供的注冊其Driver的方法, 用來注冊到DriverManager中
同樣DriverManager.getConnection()提供了獲取Connection對象的方法
在客戶端整個jdbc操作中, 例如getConnection();, registerDriver(driver);等方法全部都是針對接口的操作,

缺點

1.沒有公共或受保護構(gòu)造方法的類不能被子類化

2.很難找到這些工廠方法

靜態(tài)工廠方法的常用名稱

方法名 說明 示例
from 類型轉(zhuǎn)換方法,它接受單個參數(shù)并返回此類型的相應(yīng)實例 Date d = Date.from(instant)
of 一個聚合方法,接受多個參數(shù)并返回該類型的實例,并把他們合并在一起 Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING)
valueOf from和to更為詳細(xì)的替代方式 BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE)
instance getInstance 返回一個由其參數(shù)(如果有的話)描述的實例,但不能說它具有相同的值 StackWalker luke = StackWalker.getInstance(options)
create newInstance instancegetInstance有些類似,除了該方法保證每個調(diào)用返回一個新的實 Object newArray = Array.newInstance(classObject, arrayLen)
getType getInstance類似,但是如果在工廠方法中不同的類中使用。Type是工廠方法返回的對象類型 FileStore fs = Files.getFileStore(path)
newType newInstance類似,但是如果在工廠方法中不同的類中使用。Type是工廠方法返回的對象類型 BufferedReader br = Files.newBufferedReader(path)
type getTypenewType簡潔的替代方式 List<Complaint> litany = Collections.list(legacyLitany)

方法命名規(guī)則總結(jié)

1.通過類型轉(zhuǎn)換獲取實例:
from, valueOf, 而of是將多個對象聚合成一個
2.通過參數(shù)獲取實例:
instance, getInstance, getType(返回可復(fù)用實例)
create, newInstance, newType, Type(每次調(diào)用返回新實例)

注意Type, 表示一種類型

例如User, 對應(yīng)的方法就是newUser(), getUser(), user()

總結(jié)

總之,靜態(tài)工廠方法和公共構(gòu)造方法都有它們的用途,并且了解它們的相對優(yōu)點是值得的。通常,靜態(tài)工廠更可取,因此避免在沒有考慮靜態(tài)工廠的情況下提供公共構(gòu)造方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容