Должны ли мы избегать написания статических методов в нашем java-коде для лучшей тестируемости?

я предпочитал использовать статические методы в моем коде java, так как я думаю, что они "функциональный""без гражданства" и имеет меньше побочных эффектов. Таким образом, могут быть некоторые вспомогательные классы и методы, такие как:

public class MyHelper {
    public static Set<String> array2set(String[] items) { ... }
    public static List<String> array2list(String[] items) { ...}
    public static String getContentOfUrl(String url) {
        // visit the url, and return the content of response
    }
}

public class MyApp {
    public void doSomething() {
        String[] myarray = new String[]{ "aa","bb"};
        Set<String> set = MyHelper.array2set(myarray);
        String content = MyHelper.getContentOfUrl("http://google.com");
    }
}

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

public class ArrayHelper {
    public Set<String> array2set(String[] items) { ... }
    public List<String> array2list(String[] items) { ...}
}
public class UrlHelper {
    public String getContentOfUrl(String url) {
        // visit the url, and return the content of response
    }
}

public class MyApp {
    private final ArrayHelper arrayHelper;
    private final UrlHelper urlHelper;
    public MyApp(ArrayHelper arrayHelper, UrlHelper urlHelper) {
        this.arrayHelper = arrayHelper;
        this.urlHelper = urlHelper;
    }
    public void doSomething() {
        String[] myarray = new String[]{ "aa","bb"};
        Set<String> set = arrayHelper.array2set(myarray);
        String content = urlHelper.getContentOfUrl("http://google.com");
    }
}

в этом кстати, если мы хотим написать модульные тесты для MyApp, мы можем просто издеваются над ArrayHelper и UrlHelper и передайте их конструктору MyApp.

я полностью согласен насчет UrlHelper часть его мнения, так как исходный статический код делает MyApp непроверяема.

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

и когда использовать статические методы? Или просто избегать его использования как можно больше?


обновление:

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

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

7 ответов


просто остерегайтесь одной болезни, очень распространенной среди Java "экспертов":overengineering.

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

общим аргументом является то, что static методы проще и поэтому предпочтительный выбор, когда есть выбор. Ля метод потенциального экземпляра должен сначала доказать, что он должен быть методом экземпляра.

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


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

Так же, как стандартный Arrays.asList() (который вы, вероятно, должны использовать).

С другой стороны, доступ к внешнему URL-адресу обычно является тем, что вы хотите легко издеваться, потому что не издеваться над ним

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

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

просто не используйте статическую функцию, чтобы попытаться редактировать переменные-члены в классе (очевидно).

лично я думаю, что его хорошо использовать статическую функцию, так как она без гражданства.


статические методы должны использоваться, отвечая на вопрос " является ли этот метод функциональностью конкретного экземпляра?".

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

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


Я часто использую статические методы:

  • для заводских методов (явно именованные конструкторы)
  • чтобы обеспечить функциональный слой над объектно-ориентированным слоем, составить объекты
  • и иногда для функций общего назначения (Apache Commons имеет много хороших примеров этого)

Я никогда не использую "синглеты" (статические объекты) и методы, которые смотрите статические объекты, потому что они являются полной головной болью для тестирования и повторное использование. Я также избегаю жесткого кодирования чего-либо в статический метод, который можно было бы реально изменить. Иногда я предоставляю несколько методов-один со всеми зависимостями в качестве параметров, а другие с меньшим количеством параметров, которые вызывают более гибкий метод с некоторыми значениями по умолчанию (жестко закодированными).


java.ленг.Математика статична, что является хорошим примером. Я думал, что статики не собирают мусор, и их следует избегать, если это возможно.


нет.

как упоминал Питер Лоури в комментарии к вопросу, Java - это все об объектно-ориентированном программировании. В то время как некоторые функциональные аспекты выполнимы и помещаются в eg. Java 8, по своей сути Java не работает. static ломает так много преимуществ обучения тому, как делать современную Java - не говоря уже о всех видах не-веселых-вообще проблем с областью-что нет никакой цели их использовать если вы какой-то мастер Java кто знает, что происходит, когда вы используете это магическое ключевое слово.

вы не волшебник. Java не работает. Если хочешь стать волшебником, можешь учиться. Если вы хотите программировать функционально, посмотрите на гибридные языки, такие как Scala или Groovy, или изучите полностью функциональный мир, например. В Clojure.