Должен ли служебный класс быть статическим?


Если мне нужно создать служебный класс (например, ByteUtils или StreamUtils или StringUtils), что является лучшим выбором дизайна для них.

  • должны ли они быть статическими классами (так как у меня не будет никаких состояний для хранения)
  • должны ли они быть нестатическими классами (так что если объекты не используются, они будут gc'D)

PS: под статическим классом я подразумевал класс со статическими методами (а не внутренний статический класс)

пожалуйста, дайте советы выбор дизайна для этого ?

10 60

10 ответов:

Если это утилита общего назначения, статика лучше ИМО. Вы заявили, что у вас не будет никаких состояний для хранения, поэтому я не понимаю, почему вы должны сделать его нестатичным. Объявление его статическим также сохранит память.

мои служебные классы выглядят так:

// final, because it's not supposed to be subclassed
public final class FooUtil {

    // private constructor to avoid unnecessary instantiation of the class
    private FooUtil() {
    }

    public static int doSomethingUseful() {
    }

    // ...
}

обратите внимание, что, хотя это делает служебные методы легко тестируемыми и легко доступными извне, это также делает классы, использующие их, трудными для модульного тестирования, потому что нелегко издеваться над этими служебными методами. Наличие слишком большого количества таких классов утилит может быть признаком отсутствия OO-дизайна (процедурного программирования) и действительно может затруднить тестирование кода.

Если вы используете внедрение зависимости фреймворк (Spring, Guice, whatever), может быть хорошей идеей просто создать экземпляр класса утилиты с нестатическими методами и сделать его инъекционным синглтоном. Таким образом, классы, использующие эти служебные методы, могут быть протестированы путем издевательства над служебным объектом.

просто потому, что что-то может быть статичным, не означает, что оно должно быть статичным.

есть еще одно соображение ко всему этому: насмешка. В тестах сложнее издеваться над статическими методами, чем над поведением экземпляра класса.

разговор о ненужных выделениях кучи и GCing объектов попахивает преждевременной оптимизацией для меня. JVM будет делать довольно хорошую работу по оптимизации такого рода проблемы.

самый простой способ определить класс утилиты - это перечисление без экземпляров

public enum Utility {;
     public static int utilityMethod(int x) { /* ... */ }
}

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

вы можете иметь другие классы с сохранением состояния для конкретных целей, таких как Builder, Factory, вы можете создать объект по своему желанию и отбросить его, когда вы закончите.

хорошо сделать класс нестатическим с помощью частного конструктора:

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

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

Если вы можете сделать их статическими, то непременно это сделайте!

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

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

чистые служебные классы обычно должны быть статическими. Если у вас есть класс с четко определенными входными и выходными данными, без побочных эффектов и без состояния, то по определению это должен быть статический класс.

В общем, не добавляйте сложность (инъекция зависимостей в этом случае), прежде чем это необходимо, и в этом есть преимущество.

здесь никто не упоминает, что статические методы утилиты не являются расширяемыми. Вы не можете переопределить их. Вы не можете воспользоваться ООП (особенно полиморфизмом, который является самой мощной особенностью ООП). Это приводит к дублированию кода.

P. S. Я нашел эту статью очень полезная. http://www.yegor256.com/2014/05/05/oop-alternative-to-utility-classes.html