演化架构与紧急设计: 对设计进行重构
2009-11-05 00:00:00 来源:WEB开发网
清单 2. 第一次出现复制代码时的先兆while (enumeration.hasMoreElements()) {
final String key = enumeration.nextElement().toString();
final Object value = context.getAttribute(key);
entries.add(new Map.Entry() {
// remaining code elided, shown in Listing 1
清单 3 展示了出现第二次复制时的先兆:
清单 3. 出现第二次复制代码时的先兆while (enumeration.hasMoreElements()) {
final String key = enumeration.nextElement().toString();
final Object value = context.getInitParameter(key);
entries.add(new Map.Entry() {
// remaining code elided, shown in Listing 1
在整个 while 循环中的惟一不同之处在于 清单 2 中对 context.getAttribute(key) 的调用和 清单 3 中对 context.getInitParameter(key) 的调用之间的差别。显然,这些可以实现参数化,允许复制代码销毁自己的方法。来自 Struts 的示例解释了免费的复制和粘帖代码,这些代码不仅毫无必要,并且容易修复。
实际上,这解释了利用并将条目添加到属性集中的方法在 Struts 代码库中是一种惯用模式。允许将几乎相同的代码放到多个位置将隐藏一个事实,即 Struts 需要一直执行这个操作,这将阻止将这些代码放到一个含义更明显的位置。要清理 Struts 代码库中多个类的设计,一种方法就是意识到这种惯用模式的存在并巩固这一行为。
结构化复制
另一种复制形式更加难以检测,因此危害也更大:结构化复制。使用有限的几种语言的开发人员(特别是那些只具备少量元编程支持的语言,比如 Java 和 C#)尤其容易出现这个问题。我的同事 Pat Farley 使用了一个短语就很好地总结了结构化复制:相同的空白,不同的值。就是说,您复制了几乎一模一样的代码(即空白位置也是相同的),但是变量使用不同的值。这种复制并不会出现在 CPD 之类的工具中,因为重复的基础设施的每个实例的值必须是惟一的。尽管如此,它仍然会损害您的代码。
更多精彩
赞助商链接