Если вы будете баловать свою метафору немного ...
Вы, наверное, видели один из них раньше:
Обратите внимание, что мы называем это тостером. Мы делаем не назовем его «BreadUtil».
Аналогичным образом, методы утилиты могут и должны быть помещены в класс с именем для определенной функциональности, а не «разные вещи, связанные с хлебом»."
В большинстве случаев ваши статические методы относятся к связанному классу; например, Integer.parseInt является статическим методом класса Integer, а не членом теоретического класса IntegerUtil или NumberUtil.
В прошлом один случай создания отдельного класса утилит состоял в том, что основным классом интереса был интерфейс. Примером этого является java.util.Collections. Однако с Java 8 это не оправдание, поскольку интерфейсы могут иметь статические методы и методы по умолчанию. Фактически, Collections.sort (List) уже перенесен на List.sort.
Если у вас есть много полезных методов, и вы чувствуете, что они будут загромождать соответствующий класс, это прекрасно, чтобы помещать их в отдельный класс, но не в класс BreadUtil. Нельзя использовать слово «util» в названии класса (или «utils», «utilities», «misc», «other», «general», «shared», «common» или «framework») , Дайте классу значащее имя, которое описывает, для чего предназначены методы. Если методы слишком разнообразны, чтобы допускать такое имя класса, вам, вероятно, необходимо разделить их на несколько классов. (Небольшие классы с несколькими методами вполне приемлемы, многие даже считают, что это хороший дизайн.)
Возвращаясь к примеру Integer, если вы считаете, что методы загромождают класс, вы можете создать новые классы следующим образом:
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) { /* ... */ }
}
Всякий раз, когда вы видите класс утилиты на Java или любой язык OO, это, вероятно, индикатор того, что что-то было пропущено. То есть, в вашей модели есть какой-то объект, который должен существовать. Это возможность рассмотреть, что это может быть, чтобы вы могли сделать вашу систему более надежной и гибкой. –