Объект против статического метода

Как показано ниже, есть два простых способа, которыми я мог бы создать копир потока (бар, вводящий Apache Commons или аналогичный). На какой я должен пойти и почему?

public class StreamCopier {
private int bufferSize;

public StreamCopier() {
    this(4096);
}

public StreamCopier(int bufferSize) {
    this.bufferSize = bufferSize;
}

public long copy(InputStream in , OutputStream out ) throws IOException{
    byte[] buffer = new byte[bufferSize];
    int bytesRead;
    long totalBytes = 0;
    while((bytesRead= in.read(buffer)) != -1) {
        out.write(buffer,0,bytesRead);
        totalBytes += bytesRead;
    }

    return totalBytes;
}
}

vs

 public class StreamCopier {

 public static long copy(InputStream in , OutputStream out)
     throws IOException {
     return this.copy(in,out,4096);
 }

 public static long copy(InputStream in , OutputStream out,int bufferSize)
     throws IOException {
     byte[] buffer = new byte[bufferSize];
     int bytesRead;
     long totalBytes = 0;
     while ((bytesRead= in.read(buffer)) != -1) {
         out.write(buffer,0,bytesRead);
         totalBytes += bytesRead;
     }

     return totalBytes;
}
}

Ответ 1

Я бы пошел с нестатической (экземплярной) версией и поставлял ее потребителям в качестве явной зависимости с установщиком:

  • издевательство над модульным тестированием тогда тривиально, поэтому тесты потребителей не связаны с реализацией; Функциональность замены
  • проста, например: использование подкласса;
  • отлично работает с системами инъекций зависимостей.

Изменить

В ответ на (полезный!) комментарий "как это помогает насмехаться?", вот как это могло бы работать:

class ThingThatUsesStreamCopier {

    // our copier instance. set in constructor, but might equally use
    // a setter for this:
    private StreamCopier copier;

    public ThingThatUsesStreamCopier(StreamCopier copier) {
        this.copier = copier;
    }

    public void makeCopy(Stream in, Stream out) {
        // probably something a little less trivial...
        copier.copy(in, out);
    }
}

Когда я прихожу к тестированию ThingThatUsesStreamCopier, я могу создать mock object версию StreamCopier и создать экземпляр ThingThatUsesStreamCopier, используя этот макет.

Таким образом, я полностью контролирую поведение моего макета, поэтому мой тест отделен от любых реальных реализаций StreamCopier. Я только тестирую потребителя, а не потребитель плюс потребляемый.

Ответ 2

Я бы пошел на статическую версию, потому что нет состояния.

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

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

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

Ответ 3

Я бы пошел со статической версией.

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

Ответ 4

Все зависит от шаблона использования. Возможно, вам просто нужно скопировать что-то из InputStream в OutputStream время от времени? Тогда это, вероятно, не имеет значения. Однако, если вы делаете много копий в различных средах (сетевые потоки, как LAN, так и WAN, копируя файлы на локальном диске), вам может быть лучше, если у вас есть возможность выбрать размер буфера, используемого для копирования.

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

Ответ 5

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

Помимо прочего, статический класс также может значительно увеличить сцепление; статический класс может ссылаться из любого места, пока ссылка на ссылку ссылается. Когда дело доходит до рефакторинга, это может привести к проблемам (например, все ссылки staitc внутренне перетаскиваются в график зависимостей и т.д.).

Ответ 6

public static long copy

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

Я бы просто добавил ключевое слово final.

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

Ответ 7

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

Ответ 8

Если вы станете статичным, вы должны избегать имен WET.

WET означает запись всего дважды, поэтому вместо StreamCopier.copy назовите его

Copy.stream(in,out)

таким образом ваш код читается больше как английский.

Ответ 9

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

Ответ 10

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

Ответ 11

Статический метод означает кодирование конкретного класса, а не интерфейса. Это означает более тугое соединение и более жесткое тестирование блока. В этом случае правило "он содержит государство" падает.

Ответ 12

Когда вы статичный метод пользователя, вы вызываете его в любое время, когда он вернет тот же объект, но вы создаете new A(), он будет создавать новый объект при работе с ним