簡體   English   中英

Java最佳實踐:僅使用靜態方法的類

[英]Java best practice: Class with only static methods

我有一個應用程序,我有一個名為PlausibilityChecker的類。 該類只有靜態方法,如checkZipcodeFormatcheckMailFormat 我在GUI類中使用它們來檢查輸入,然后再將它發送到較低層。

這是好習慣嗎? 我以為我只使用靜態方法,所以我不必關心將實例傳遞給GUI類或者在每個gui類中都有一個不引用gui對象的實例字段。

我注意到Java NIOFiles類只有靜態方法所以我認為這不是那么可怕的錯誤。

我會說你做得對。 除此之外,您的實用程序類的一些建議:

  • 確保它沒有任何狀態。 也就是說,除非它被聲明為static final否則類中沒有字段。 此外,請確保此字段也是不可變的,例如String s。
  • 確保它不能是其他類的超類。 使類成為final以便其他程序員無法擴展它。
  • 這個是有爭議的,但你可以聲明一個非arg構造函數private ,所以沒有其他類可以創建你的實用程序類的實例(使用反射或類似的東西會做,但沒有必要去保護類)。 你為什么不這樣做? 嗯,這是一個奇怪的情況,你需要/需要注入實用程序類的實例,例如通過接口,而不是直接在你的類中使用它。 這是一個例子 這種設計很奇怪但可能會發生(如上面的鏈接所示),但如果你不能在這種情況下運行,最好的建議是保持構造函數是private

有很多庫提供實用程序類,以幫助程序員完成我們的工作。 其中最着名的是Apache Common庫集。 它是開源的,您可以檢查代碼,看看他們如何設計這些實用程序類以創建您的。 (免責聲明:我不工作或支持這些庫,我是他們的快樂用戶)

重要說明: 避免在實用程序類中使用單例

在Java 8中,您現在可以將靜態實用程序類更改為具有靜態實現的接口。 這消除了使類最終並且必須提供私有構造函數的需要。 它就像將'class'更改為'interface'並刪除最后一個單詞(如果你擁有它)一樣簡單(所有接口都是抽象的,所以它們不能是最終的)。 由於接口方法始終是公共的,因此您可以從中刪除任何公共范圍。 如果您有一個私有構造函數,那么也刪除它(您無法使用構造函數編譯接口,因為它們無法實例化)。 它的代碼更少,看起來更干凈。 您不必重構已經使用它的任何類。

不要擔心子類化或實例化。 JDK中的以下實用程序類可以進行子類化或實例化,但是在這些年中沒有人濫用它們。 人不是那么愚蠢。

java.beans.Beans
java.beans.PropertyEditorManager
java.lang.invoke.LambdaMetafactory
java.lang.reflect.Modifier
java.net.URLDecoder                                   ...but not URLEncoder:)
javax.management.DefaultLoaderRepository
javax.management.Query
javax.management.loading.DefaultLoaderRepository
javax.management.relation.RoleStatus
javax.print.ServiceUI
javax.swing.UIManager
javax.swing.plaf.basic.BasicBorders
javax.swing.plaf.basic.BasicGraphicsUtils
javax.swing.plaf.basic.BasicHTML
javax.swing.plaf.basic.BasicIconFactory
javax.swing.plaf.metal.MetalBorders
javax.swing.plaf.metal.MetalIconFactory
javax.swing.text.Utilities
javax.swing.text.html.HTML

但是,作為公共API,您確實要禁止默認構造函數,否則javadoc頁面上有一個未記錄的構造函數,這是一個笨拙且令人困惑的問題。 對於您自己的內部API,沒關系,沒人關心。

但是沒有理由壓制子類化。 如果有人想要將實用程序類子類化,無論出於何種原因,請讓他。 當然,私有構造函數會將子類化作為副作用來抑制。


在java8中,有更多的設計可能性需要考慮 -

一個包含所有靜態方法的接口 - 這與具有所有靜態方法的類一樣好。 接口和類都沒有為此目的而設計,因此任何一個都可以。 但是,不要指望在接口的子類型中繼承這些靜態方法 - 接口靜態方法不可繼承。 使用接口的一個優點是我們不需要抑制默認構造函數出現在javadoc上。

具有所有默認方法的接口 - 通過繼承訪問。 這很有趣,但總的來說有問題(繼承僅適用於非靜態上下文)。 但它可能是某些API設計中更好的選擇,例如,這個html構建器 API。

如果你只是為其他類提供“工具”的方法,這為什么不是好的做法。

只有靜態方法的類是Java中用於實用程序方法的常見模式。 標准庫中的示例包括FilesCollectionsExecutor

對於這樣的實用程序類,最好確保不能實例化您的類,以使類的意圖清晰。 您可以通過顯式聲明私有構造函數來實現。 有關詳細信息,請參閱項目4:使用 Josh Bloch的“Effective Java”中的私有構造函數強制執行非實例化

單身人士可以,具體取決於具體情況。

出於測試目的,您可能想要模擬對單例的引用以避免單元測試期間的副作用。 在這種情況下,使用依賴注入框架(如Spring)來處理實例的創建並使用可以覆蓋的常規方法而不是靜態方法可能是有意義的。

如果仍計划使用靜態方法,請確保在多線程上下文中使用時調用是線程安全的。 (例如雙重檢查鎖定)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM