Очень повторяющийся код, как правило, плохой, и есть шаблоны проектирования, которые могут помочь свести это к минимуму. Однако иногда это просто неизбежно из-за ограничений самого языка. Возьмите следующий пример из java.util.Arrays
:
/**
* Assigns the specified long value to each element of the specified
* range of the specified array of longs. The range to be filled
* extends from index <tt>fromIndex</tt>, inclusive, to index
* <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, the
* range to be filled is empty.)
*
* @param a the array to be filled
* @param fromIndex the index of the first element (inclusive) to be
* filled with the specified value
* @param toIndex the index of the last element (exclusive) to be
* filled with the specified value
* @param val the value to be stored in all elements of the array
* @throws IllegalArgumentException if <tt>fromIndex > toIndex</tt>
* @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
* <tt>toIndex > a.length</tt>
*/
public static void fill(long[] a, int fromIndex, int toIndex, long val) {
rangeCheck(a.length, fromIndex, toIndex);
for (int i=fromIndex; i<toIndex; i++)
a[i] = val;
}
Вышеприведенный фрагмент кода появляется в исходном коде 8 раз с очень небольшим изменением в сигнатуре документа/метода, но точно таким же телом метода, по одному для каждого из типов корневого массива int[]
, short[]
, char[]
, byte[]
, boolean[]
, double[]
, float[]
и Object[]
.
Я считаю, что если кто-то прибегает к размышлению (что само по себе совершенно другое), это повторение неизбежно. Я понимаю, что в качестве класса полезности такая высокая концентрация повторяющегося кода Java очень нетипична, но даже с лучшей практикой повторение происходит! Рефакторинг не всегда работает, потому что это не всегда возможно (очевидный случай, когда повторение содержится в документации).
Очевидно, что поддерживать этот исходный код - это кошмар. Небольшая опечатка в документации или незначительная ошибка в реализации умножается на количество повторений. Фактически, лучший пример включает этот точный класс:
Ошибка является удивительно тонкой, что происходит в том, что многие считают простым и простым алгоритмом.
// int mid =(low + high) / 2; // the bug
int mid = (low + high) >>> 1; // the fix
Вышеприведенная строка появляется 11 раз в исходном коде!
Итак, мои вопросы:
- Как эти повторяющиеся Java-код/документация обрабатываются на практике? Как они разрабатываются, поддерживаются и тестируются?
- Вы начинаете с "оригинала" и делаете его как можно более зрелым, а затем копируете и вставляете по мере необходимости и надеетесь, что не допустили ошибку?
- И если вы допустили ошибку в оригинале, тогда просто исправьте ее повсюду, если вам не удобно удалять копии и повторять весь процесс репликации?
- И вы применяете этот же процесс для тестового кода?
- Может ли Java использовать некоторую предварительную обработку исходного кода с ограниченным использованием для такого рода вещей?
- Возможно, у Sun есть свой препроцессор, который помогает писать, поддерживать, документировать и тестировать этот повторяющийся код библиотеки?
Комментарий запросил другой пример, поэтому я вытащил его из Google Collections: com.google.common.base.Predicates строки 276-310 (AndPredicate
) по линиям 312-346 (OrPredicate
).
Источник для этих двух классов идентичен, за исключением:
-
AndPredicate
vsOrPredicate
(каждый из них появляется 5 раз в своем классе) -
"And("
vsOr("
(в соответствующих методахtoString()
) -
#and
vs#or
(в комментариях@see
Javadoc) -
true
vsfalse
(вapply
;!
можно переписать из выражения) -
-1 /* all bits on */
vs0 /* all bits off */
inhashCode()
-
&=
vs|=
inhashCode()