2016-12-06 51 views
8

在Java中創建實用程序(不包含任何狀態)類的最佳實踐是什麼?在Java中創建無狀態實用程序類的最佳實踐是什麼

在大多數情況下,我們最終都會爲這些任務創建靜態方法。 其他可能的方式可能是「創建單體對象」來執行此操作。

當需求是代碼時應該怎麼設計考慮應該很容易單元測試?

+5

無論何時您看到Java或任何OO語言的實用程序類,都可能表示某些內容已丟失。也就是說,你的模型中有一些對象需要存在。這是一個考慮可能的機會,所以您可以使您的系統更具可測試性和靈活性。 –

回答

4

我認爲最常見的方法是創建靜態方法。舉例來說,參見StringUtils in Apache Commons Lang,Strings in Guava或甚至Arrays in JDK

此外,該類應該是最終的,它應該有一個私有構造函數,以避免繼承或實例化它。

要麼你使用靜態方法或單例,它應該是相同的努力,單元測試它。在後一種情況下,你可能會寫更多的代碼(字符)。

我知道面向對象的純粹主義者會爭論這些類的存在,我會傾向於同意他們,但這些僅僅是爲了簡單起見而添加的,您應該限制這些類的數量。

0

如果您使用Spring之類的框架,您可以使用@Service註釋創建一個實用程序類。 這將確保它是單一實例(SIngleton),並且可以簡單地將它注入到任何其他需要使用其方法的類中。

在任何其他情況下,我建議使用工廠模式或cotrast使用靜態方法使其成爲單例。

0

Static是單身人士。使用非靜態方法的單例實例只有在需要使用不同屬性(多個)/設置(多個)值的多個Utility類變體時才需要。例如,當您的實用程序具有某些屬性(即customProperty)並且您同時需要兩個不同的案例時。

  1. 工具時需要使用CustomProperty的=值

  2. 時Utitlity需要使用CustomProperty的=數值...

,但它是很奇怪的,笨拙,也不好..實用程序調用者可以將所需的屬性值提供給靜態方法。所以,不要因此而陷入困境。 make實用方法總是靜態的,不關心的「理論」模式... :)

9

如果你滿足我的比喻有點...

你可能已經看到這些人之前:

Device

請注意,我們稱之爲烤麪包機。我們做而不是稱之爲「BreadUtil」。

同樣,實用方法可以也應該放在一個名爲特定功能的類中,而不是「與麪包相關的雜項。「

大多數情況下,您的靜態方法屬於相關的類;例如,Integer.parseInt是Integer類的靜態方法,不是理論IntegerUtil或NumberUtil類的成員。

過去,創建單獨的工具類的一種情況是當主要類感興趣的是接口。一個例子是java.util.Collections。但是,從Java 8開始,這不是一個藉口,因爲接口可以有靜態方法和默認方法。實際上,Collections.sort(List)已經被遷移到List.sort

如果您有很多實用方法,並且您覺得他們會混淆相關類,可以將它們放在單獨的類中,但不是「BreadUtil」類。在類名(或「utils」,「utilities」,「misc」,「miscellaneous」,「general」,「shared」,「common」或「framework」)中放置「util」這個詞是不可接受的。 。給班級一個有意義的名字,描述這些方法的用途。如果方法太多而不能容許這樣的類名,那麼你可能需要將它們分成多個類。 (只有很少幾種方法的小班是完全可以接受的;許多人甚至認爲這是一個好的設計。)

回到整數示例,如果您覺得方法混淆了類,則可以創建如下這樣的新類:

public class IntegerMath { 
    private IntegerMath() { } 

    public static int compare(int x, int y) { /* ... */ } 
    public static int compareUnsigned(int x, int y) { /* ... */ } 
    public static int divideUnsigned(int dividend, int divisor) { /* ... */ } 
    public static int min(int a, int b) { /* ... */ } 
    public static int max(int a, int b) { /* ... */ } 
    public static int remainderUnsigned(int dividend, int divisor) { /* ... */ } 
    public static int signum(int i) { /* ... */ } 
    public static int sum(int a, int b) { /* ... */ } 
    public static long toUnsignedLong(int i) { /* ... */ } 
} 

public class IntegerBits { 
    private IntegerBits() { } 

    public static int bitCount(int i) { /* ... */ } 
    public static int highestOneBit(int i) { /* ... */ } 
    public static int lowestOneBit(int i) { /* ... */ } 
    public static int numberOfLeadingZeros(int i) { /* ... */ } 
    public static int numberOfTrailingZeros(int i) { /* ... */ } 
    public static int reverse(int i) { /* ... */ } 
    public static int reverseBytes(int i) { /* ... */ } 
    public static int rotateLeft(int i, int distance) { /* ... */ } 
    public static int rotateRight(int i, int distance) { /* ... */ } 
} 

public class IntegerParser { 
    private IntegerParser() { } 

    public static int parseInt(String s) { /* ... */ } 
    public static int parseInt(String s, int radix) { /* ... */ } 
    public static int parseUnsignedInt(String s) { /* ... */ } 
    public static int parseUnsignedInt(String s, int radix) { /* ... */ } 
} 

最後的是,可能是沒有靜態方法更好的東西的例子:

public class IntegerParser { 
    public IntegerParser() { this(10); } 
    public IntegerParser(int radix) { /* ... */ } 

    public int parseInt(String s) { /* ... */ } 
    public int parseUnsignedInt(String s) { /* ... */ } 
} 
0

什麼是用於創建實用的最佳實踐(不HOL d任何狀態)在Java中的類。

在我看來,最好的方法是儘可能省略實用程序類。

實用類反轉了面向對象編程的思想。當你發現你需要一種新方法時,你通常會把它添加到具有最高凝聚力的課堂上。這意味着需要掌握方法所需信息的類。其他信息將作爲參數傳遞給方法。如果參數列表太長,通常是錯誤放置方法的指標。

當您確實需要實用程序類來爲某種類型提供方法時,存在少數情況。例如。

  • 如果你不能將方法添加到源代碼,因爲你不擁有它(但你也許可以創建一個包裝或者它的子類)
  • 如果需要額外的方法的類是final你沒有自己的源代碼(例如StringUtility)

在大多數的我們最終創造了這樣的任務靜態方法的情況下。其他可能的方式可能是「創建單個對象」來執行此操作。

當需求是代碼時應該怎麼設計考慮應該很容易單元測試?

如果您從單元測試性的角度來看實用程序類,並且希望能夠模擬實用程序類,則應該使用單例,因爲可以替換對象引用。

通過改變單例實例引用(靜態變量)或通過使用對象字段在客戶端。例如。

private SomeUtility someUtility = SomeUtiltiy.INSTANCE; 

public void someMethod(...){ 
    // Can be replaced by changing the someUtility reference 
    someUtility.doSomething(....); 

    // A static call like 
    // SomeUtility.doSomething(...); 
    // can not be easily replaced. 
} 

靜態方法調用很難替換。通過重寫客戶端字節碼,一些測試框架如powermock支持mocking of static calls。但我認爲這些框架旨在支持糟糕的遺留代碼的單元測試。如果你需要新代碼的powermock,你應該重新考慮你的設計。

+0

如果您創建通用字符串或數組操作的庫,該怎麼辦?這通常是公用事業類的目的。簡單類型或對象的基元(或不那麼原始)操作。 –

相關問題