管理高度重复代码和文件Java
-
22-09-2019 - |
题
高度重复代码通常是一件坏事,还有设计的模式,可以帮助尽量减少这一点。但是,有时这简直是不可避免的由于制约语言本身。采取以下例子 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[]
.
我相信,除非一个度假胜地,以反映(这是一个完全不同的问题本身),这种重复是不可避免的。我的理解是,作为一个实用工具类,这样的高浓度的重复代码是高度不典型,但是即使有最好的做法, 重复不会发生!重构并不总是工作,因为它并不总是可能的(明显的情况是重复的文件中).
显然维持这源代码是一个噩梦。一个微小的错误的文件,或一个小错误执行、乘以过多的重复。事实上,最好的例子发生涉及这一确切类:
谷歌的研究博客-额外的额外阅读所有有关:几乎所有的二进制的搜索和Mergesorts被破坏(由约书亚布洛赫、软件工程师)
错误是一个令人惊讶的微妙之一,发生在许多人认为是仅仅是一个简单的和直接的算法。
// int mid =(low + high) / 2; // the bug
int mid = (low + high) >>> 1; // the fix
上线 出现11次的源代码!
所以我的问题是:
- 怎么是这种重复代码/文件处理在实践中?他们是如何开发、维护和测试?
- 你开始与"原始",并把它作为成熟,因为可能,然后再复制和粘贴为必要和希望你没有做错了吗?
- 如果你没有犯错误的原始,然后只是修复它无处不在,除非你舒服删除的副本和重复整个复制的过程?
- 和你申请这一相同过程中测试的代码吗?
- 会Java受益于某种有限使用的源代码的预处理这种事情?
- 也许太阳都有自己的预处理,以帮助编写、维持、文件和测试这种重复的图书馆的代码?
一种意见要求的另一个例子,所以我把这个从Google的集合: com.谷歌。常见的。基础。谓 线276-310(AndPredicate
)与行312-346(OrPredicate
).
源于这两类完全相同,除非:
AndPredicate
vsOrPredicate
(每出现5次在其类)"And("
vsOr("
(在相应的toString()
方法)#and
vs#or
(在@see
如果是的话,为什么不试的意见)true
vsfalse
(在apply
;!
可以改写的表达)-1 /* all bits on */
vs0 /* all bits off */
在hashCode()
&=
vs|=
在hashCode()
解决方案
对于人,绝对需要的性能,拳击和拆箱和generified集和诸如此类的东西是很大的,没有-没有。
同样的问题中发生的性能计算在你需要同样复杂的工作两者对于浮动和双人(说的一些方法显示在Goldberd的 "什么每一个计算机科学家应该知道的浮点数" 纸张)。
还有一个原因为什么 宝库's TIntIntHashMap
运行环绕Java HashMap<Integer,Integer>
工作时,与一个类似数量的数据。
现在怎么样宝库收集的源代码写的?
通过使用源码仪器当然:)
有几个Java库对更高性能(大高于默认Java那些)使用代码的发电机,以创建的重复的源码。
我们都知道,"源代码仪器仪表"是邪恶的,该代码生成的废话,但仍然那是怎样的人真的知道他们在做什么(即这样的人写的东西喜欢库):)
为什么它值得我们产生的源代码,其中包含大警告,如:
/*
* This .java source file has been auto-generated from the template xxxxx
*
* DO NOT MODIFY THIS FILE FOR IT SHALL GET OVERWRITTEN
*
*/
其他提示
如果你绝对必须重复代码,按照非常好的例子你已经给和组的所有代码在一个地方,在那里很容易找到和解决的时候,你必须做出改变。文件的重复,更重要的是, 原因重复 这样,大家谁来后你意识到这两者。
从 维基百科 不要重复自己(干)或重复是邪恶(死亡)
在某些情况下,这种努力需要强制执行干哲学可以大于努力,以保持单独的数据副本。在其他一些情况下,重复的信息是不可改变或保持在控制紧张足以使干不需要的。
有可能是没有答案或技术,以防止类似的问题。
甚至花哨的裤子的语言,如Haskell有重复代码(看看我的岗位上haskell和化)
这似乎有三种选择这个问题:
- 使用反射和失去的性能
- 使用预处理像的模板Haskell或Caml4p等同于语言和生活污秽
- 或者我的个人最喜欢的使用宏如果你的语言支持(方案,并且口齿不清)
我认为该宏不同于进行预处理,因为宏通常是在同样的语言,该目标是作为进行预处理的是不同的语言。
我认为List/方案宏将解决许多的这些问题。
我说,太阳已经到文件这样的Java SE图书馆的代码也许其它的第3次缔约方图书馆作家也这么做。
然而,我认为这是一个彻底废物复制和粘贴文件全文件这样的代码,只有用于家。我知道很多人会不同意,因为它将使他们在房子JavaDocs看起来不太干净。然而,这种交易,使他们的代码变得更加清洁而,在我看来,是更加重要。
Java基本类型螺丝你,特别是当它涉及到阵列。如果你具体地询问代码,涉及基本类型,然后我要说的只是试着避免他们。对象[]方法是足够的,如果你用盒装的类型。
在一般情况下,需要大量的单元测试并没有真的没有别的事要做,除诉诸反映。像你说的,这是另一个问题完全,但不要太害怕的反映。写的DRYest码你可以首先,然后简介并确定如果反射性的打击真的是够糟糕的逮捕令写出来并保持的额外的代码。
你可以使用代码生成器构造的变化码使用的模板。在这种情况下,java源是一种产品的发电机和真正的代码是模板。
鉴于两个代码碎片称是类似的,大多数语言的有限的设施对于构筑的抽象概念,统一代码碎片进入一个整体。抽象的时候你的语言不能这样做,你要步骤以外的语言:-{
最一般的"抽象"机制是一个完整的宏处理其可申请任意的计算的"宏体"而实例,它(觉得 后或串-重写 系统,这是图灵,能够). M4 和 GPM 是典型的例子。C预处理器不是其中之一。
如果你有这样的宏处理,可以构造一个"抽象"作为一个宏观和运行的宏处理上你的"抽象的"源文产生实际的源代码汇编和运行。
你也可以使用更多的限制版本的理念,往往被称为"代码发电机".这些通常不是图灵能力,但在许多情况下,他们的工作不够好。这取决于如何复杂的你的"宏实例"的需要。(的的原因,人们都迷恋C++模板机制部份,尽管它丑陋的, 是 图灵能力和使人们可以做真的丑陋的,但令人惊讶的代码生成的任务与它)。另一个答案在这里提到的宝库,这显然是在更为有限,但仍然非常有用的类别。
真的很一般的宏处理(如M4)操纵,只是文字;即使他们强大,但他们不处理结构的编程语言好吧,这真是尴尬写一generaor在这样一个mcaro处理器,不仅可以产生的代码,但是优化所产生的结果。大多数代码的发电机,我遇到的是"插入这串入这串模板",因此无法做任何优化所产生的结果。如果你想产生的任意代码和高性能引导,你需要的东西那是图灵能力,但理解该结构产生的代码,所以它可以很容易地操作(例如,优化))。
这样的一个工具,称为 程序的转换系统.这样的一个工具分析的来源的文字只是喜欢一个编译器,并进行分析/转换到实现所希望的效果。如果你可以把标记在来源文的程序(e。g、结构性的评论或注释的语言,他们)指挥的程序transformaiton工具做什么,然后你可以用它来进行这种抽象的实例,代码生成的,和/或代码优化。(一张海报的建议的挂钩到Java编译是一个变化对这一想法)。使用一般puprose转换系统(例如 DMS软件再造无线工具包 意味着你可以这样做基本的任何语言。
很多这种重复现在可以被避免感谢仿制药。他们是天赐当编写同样的代码,其中只有类型的变化。
可悲的是,虽然,我认为,通用数组仍然没有得到很好的支持。至少在目前,使用集装箱,允许您可以利用的仿制药。多态性也是一个有用的工具,以减少这种代码重复。
来回答你的问题是关于如何处理代码,绝对必须重复...标记每一个实例很容易搜索的评论意见。有一些java预处理器,加入C式宏。我想我还记得//需要将物品寄具有一个。