高度重复的代码通常是一件坏事,有一些设计模式可以帮助减少这种情况。但是,有时由于语言本身的限制,这只是不可避免的。从以下示例中获取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 代码是非常不典型的,但即使采用最佳实践,重复也会发生!重构并不总是有效,因为它并不总是可能的(明显的情况是文档中有重复)。
显然维护这个源代码是一场噩梦。文档中的轻微错字或实现中的小错误会乘以多次重复。事实上,最好的例子恰好涉及到这个确切的类:
谷歌研究博客 - 额外的,额外的 - 阅读所有相关信息:几乎所有的二进制搜索和合并排序都被破坏了(作者 Joshua Bloch,软件工程师)
这个错误非常微妙,发生在许多人认为只是一种简单直接的算法中。
// int mid =(low + high) / 2; // the bug
int mid = (low + high) >>> 1; // the fix
上面的代码在源代码中出现了 11 次!
所以我的问题是:
- 在实践中如何处理这些重复的 Java 代码/文档?它们是如何开发、维护和测试的?
- 你是从“原版”开始,尽可能的成熟,然后根据需要复制粘贴,希望你没有弄错?
- 如果您确实在原始文件中犯了错误,那么只需在所有地方进行修复,除非您对删除副本并重复整个复制过程感到满意?
- 你也对测试代码应用同样的过程吗?
- Java 会从针对此类事物的某种有限使用源代码预处理中受益吗?
- 也许 Sun 有自己的预处理器来帮助编写、维护、记录和测试这些重复的库代码?
评论要求另一个示例,所以我从 Google 集合中提取了这个示例:com.google.common.base.Predicates第 276-310 行(AndPredicate
)与第 312-346 行(OrPredicate
)。
这两个类的来源是相同的,除了:
AndPredicate
vsOrPredicate
(每个在同类中出现 5 次)"And("
vsOr("
(在各自的toString()
方法中)#and
vs#or
(在@see
Javadoc 注释中)true
vsfalse
(inapply
;!
可以改写出表达式)-1 /* all bits on */
与0 /* all bits off */
在hashCode()
&=
与|=
在hashCode()