2009-11-24 3 views
10

Как показано ниже, есть два простых способа, которыми я мог бы сделать копир потока (бар, вводящий 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; 
} 
} 

против

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; 
} 
} 
+0

.. есть ошибка в первом «копию» метод во втором примере - третий параметр должен быть удален. Может быть, кто-то может применить исправление!? –

ответ

19

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

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

Редактировать

В ответ на (полезный!) Комментарием «как это поможет насмешки?», Вот как это может работать:.

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, я могу создать версию StreamCopiermock object и экземпляр ThingThatUsesStreamCopier с помощью этого издеваться

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

+2

+1, выкрикивая статические методы почти невозможно. –

+2

Итак, вот что я не понимаю об этом аргументе: с версией экземпляра пользователь просто скажет «new StreamCopier(). Copy (in, out)». Как это легче осмеиваться или заменять? –

+0

Использование статических методов также затрудняет создание связанных подклассов StreamCopier в будущем. – hallidave

11

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

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

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

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

+0

Почему смена сердца? – stuart

+1

Труднее проверить код, который зависит от статических методов, потому что сложнее переопределить поведение статических методов. В моем опыте работы с Java и C#, способным высмеивать объект, приводит к гораздо более быстрой разработке тестов, чем использование библиотеки для переопределения статических методов. – dice

0

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

6

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

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

+1

«Золотые слова», чтобы заставить вызывающего создать объект, чтобы вызвать метод »! –

2

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

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

+1

Термин 'singleton' здесь немного неуместен. – BalusC

+0

Это больше похоже на дополнительный синглтон, вы знаете? Как одиночный, но не совсем. :) (Да, может быть, мне нужно использовать какой-то другой термин. Существуют ли какие-либо условия для псевдоселетонов?) – Bombe

+0

По умолчанию? :) – Groo

1

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

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

1
public static long copy 

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

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

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

1

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

0

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

1

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

WET означает запись всего два раза, таким образом, вместо того, чтобы назвать его StreamCopier.copy

Copy.stream(in,out) 

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

+0

Я не слишком уверен в этом, наличие класса «Копия» кажется немного шире. Если вам нужно было написать функцию копирования для полностью несвязанной сущности, будет ли метод также проходить в классе «Копировать»? – JonoW

+2

'Streams.copy (in, out)' звучит неплохо. –

+0

@jonow это будет. На самом деле это так, как я организую все мои вспомогательные методы. 'Any.satisfy',' All.notNull' и т. Д. Конечно (если у вас нет частичных классов, как на C#), это предполагает замкнутый мир, поскольку в некоторых публичных проектах он может не предоставляться. – akuhn

0

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

0

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

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