2016-12-06 2 views
8

Какова наилучшая практика для создания классов Utility (которые не содержат состояний) в Java.Какова наилучшая практика для создания классов Utility Utility в Java

В большинстве случаев мы создаем статические методы для таких задач. Другим возможным способом может быть «создание одиночных объектов» для выполнения этой операции.

Какое должно быть соображение дизайна, когда требование - это код, который должен легко тестироваться?

+5

Всякий раз, когда вы видите класс утилиты на Java или любой язык OO, это, вероятно, индикатор того, что что-то было пропущено. То есть, в вашей модели есть какой-то объект, который должен существовать. Это возможность рассмотреть, что это может быть, чтобы вы могли сделать вашу систему более надежной и гибкой. –

ответ

4

Я думаю, что наиболее распространенным способом является создание статических методов. В качестве примера см. StringUtils in Apache Commons Lang, Strings in Guava или даже Arrays in JDK.

Также класс должен быть окончательным, и он должен иметь частный конструктор, чтобы не наследовать его или не создавать его.

Либо вы используете статические методы, либо синглтон, это должно быть такое же усилие, чтобы его тестировать. В последнем случае вы можете написать немного больше кода (символов).

Я знаю, что пуристы ОО будут спорить о самом существовании таких классов, и я склонен согласиться с ними, но они добавляются только ради простоты, и вы должны ограничить количество таких классов.

0

Если вы используете фреймворки типа Spring, вы можете создать полезный класс с аннотацией @Service. Это гарантирует, что это единственный instace (SIngleton), и простой способ ввести его в любой другой класс, который будет иметь потребность в его методах.

В любом другом случае я предлагаю сделать его одноэлементным, используя заводской шаблон или в cotrast, используя только статические методы.

0

Статический однотонный. Singleton-экземпляр с нестационарными методами необходим только тогда, когда вам нужно несколько вариантов класса Utility с различными значениями (-ами) использования/значений (-ов) для использования. В качестве примера, когда ваша утилита имеет некоторое свойство (т. Е. CustomProperty), и вам нужно два разных случая одновременно.

  1. когда утилита нужно использовать CustomProperty = value1

  2. когда Utitlity нужно использовать CustomProperty = значение2 ...

но это довольно странно, неуклюжи и не хорошо .. . Утилита утилит может предоставить необходимое значение свойства в статический метод. Итак, не зацикливайтесь на этом. Сделать методы Подсобные всегда статичны и не заботятся о «теоретических» моделей ... :)

9

Если вы будете баловать свою метафору немного ...

Вы, наверное, видели один из них раньше:

Device

Обратите внимание, что мы называем это тостером. Мы делаем не назовем его «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) { /* ... */ } 
} 
0

что лучшая практика для создания утилиты (которые не хол d любых состояний) на Java.

На мой взгляд, лучший способ - опустить классы полезности, когда это возможно.

Класс утилиты отменяет идею объектно-ориентированного программирования. Когда вы дойдете до того, что вам нужен новый метод, вы обычно добавляете его в класс с наивысшей связностью. Это означает класс, который содержит большую часть информации, которая нужна методу. Другая информация будет передана в качестве параметров. Если список параметров слишком длинный, он часто является индикатором неуместного метода.

Редкие ситуации, когда вам действительно нужен класс утилит для предоставления метода для определенного типа. Например.

  • если вы не можете добавить метод к исходному коду, потому что вы не являетесь его владельцем (но вы можете либо создать оболочку или подкласс)
  • если класс, который необходим дополнительный метод является окончательным и вы не являетесь владельцем исходного кода (например, StringUtility)

В большинстве случаев мы в конечном итоге создать статические методы для таких задач. Другим возможным способом может быть «создание одиночных объектов» для выполнения этой операции.

Какое должно быть соображение дизайна, когда требование - это код, который должен легко тестироваться?

Если вы посмотрите на классы полезности с точки зрения объективности тестирования и хотите быть в состоянии высмеять класс utiltiy, вы должны использовать singleton, потому что ссылки на объекты могут быть заменены.

Либо путем изменения ссылки экземпляра singleton (статической переменной), либо на стороне клиента с помощью поля объекта. Например.

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

Что делать, если вы создаете библиотеку общих операций с строкой или массивом? Это то, что обычно служит целью для классов полезности. Примитивные (или не очень примитивные) операции над простыми типами или объектами. –

Смежные вопросы