高度重复的代码通常是不好的事情,并且有些设计模式可以帮助最大程度地减少这种情况。但是,由于语言本身的限制,有时这是不可避免的。以以下示例为例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代码非常不典型,但是即使采用最佳实践,重复也确实会发生!重构并非总是可行,因为它并非总是可能的(显而易见的情况是文档中有重复项)。
显然,维护此源代码是一场噩梦。无论进行多少次重复,文档中的轻微错字或实现中的次要错误都会成倍增加。实际上,最好的例子恰好涉及此确切的类:
Google Research博客-额外,额外-全部阅读:几乎所有二进制搜索和合并排序均被破坏(软件工程师Joshua Bloch)
该错误是一个令人惊讶的微妙错误,发生在许多人认为只是一种简单明了的算法中。
// int mid =(low + high) / 2; // the bug
int mid = (low + high) >>> 1; // the fix
上一行在源代码中出现11次!
所以我的问题是:
- 在实践中如何处理这些重复的Java代码/文档?如何开发,维护和测试它们?
- 您是从“原始”开始,并使其尽可能成熟,然后根据需要复制并粘贴,希望您没有记错吗?
- 而且,如果您确实在原件上犯了一个错误,那么就将它修复到所有地方,除非您愿意删除副本并重复整个复制过程?
- 您是否也将相同的过程应用于测试代码?
- Java是否会从这种用途受限的源代码预处理中受益?
- 也许Sun有自己的预处理器来帮助编写,维护,记录和测试这些重复的库代码?
评论要求提供另一个示例,因此我从Google Collections中提取了这个示例:com.google.common.base。谓词AndPredicate
为276-310行()和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 */
中hashCode()
&=
VS|=
中hashCode()