我很难理解DRY原理
1) 我知道DRY原则的目的是避免信息的重复,但术语information
在DRY的上下文中指的是什么?它只指the state of the object
(即Person
实体应该只有一个表示其birth data
的属性),还是该术语也指behavior of the object
(即Dog
实体应该只有一个表示barking behavior
的方法)
2) 问题假设术语information
也指behavior
:
DRY就是不重复相同的信息,我将其解释为我们不应该有两个或多个方法/代码片段做完全相同的事情。但我认为术语repetition
在DRY?也就是说,我看到过DRY也应用于具有类似行为的方法/代码片段的例子(因此这些方法/代码段并没有做完全相同的事情),但这些方法/码片段随后被替换为单个方法/码段?!
感谢
1)"信息"是指代码的任何一段:
- 从一个大的代码片段中(手动计算一个数字的平方根应该用Sqrt方法代替)
- 到一个简单的值(到处使用字符串"Monday",应该替换为一周中的天数枚举)
2) 如果两种方法相似,那么可以认为其中的某些部分做的事情完全相同。如果是这样的话,并且如果可以将这两种方法中的逻辑泛化来解决一个通用问题,而不是两个特定问题,那么应该对它们进行重构,以符合DRY原则。
如果推广整个算法是不可行的,那么至少考虑重构做完全相同事情的部分。
DRY主体的存在主要是为了使增强和维护更容易。其想法是,每次引入重复时,可维护性和可扩展性都会下降。这里有两个例子:
重复的代码
public class Dog {
int barkCount = 0;
public void bark(){
println "bark";
barkCount++;
}
public void defendHouse(){
println "bark";
barkCount++;
println "run in circles";
}
}
虽然这个例子有些原始,但您会看到bark中的逻辑在defensedHouse中是重复的。这是不可取的,原因有几个:
- 代码更难阅读(更长、更多的部分,开发人员必须注意重复)
- 代码更难维护(开发人员在更新bark()逻辑时可能会忘记更新defensedHouse()逻辑。)
这两个要点都是长寿软件的重要考虑因素(提示:所有软件都是长寿的),因为它们是每次更改/读取所产生的经常性成本。如果重复发生在更远的距离上,情况会更糟——例如,重复的逻辑可能在不同的文件或包中。
重复的数据
public class Person {
String birthDay = null;
Date birthDate = null;
public void setBirthDate(Date newDate){
birthDate = newDate;
birthDay = newDate.getDayOfWeek();
}
public void clearBirthDate(){
birthDate = null;
birthDay = null;
}
public String getBirthDay(){
if(newDate == null){
return null;
} else {
return newDate.getDayOfWeek();
}
}
}
这里的问题是出生日是出生日期的一个子集。这里最大的问题是:
- 数据完整性:当另一个字段发生更改时,开发人员可能无法更新一个字段。很难保证一致性(例如,如果newDate.getDayOfWeek()抛出异常,则字段可能会不同步)
- 可读性:这段代码更难阅读,因为开发人员必须注意到birthDay和birthDate是相关联的(但只能按照惯例)
为了完整起见,这里有两个改进的例子,以及我对何时违反DRY原则的思考。。。
清理:重复的代码
public class Dog {
int barkCount = 0;
public void bark(){
println "bark";
barkCount++;
}
public void defendHouse(){
bark();
println "run in circles";
}
}
清理:重复的数据
public class Person {
Date birthDate = null;
public void setBirthDate(Date newDate){
birthDate = newDate;
}
public void clearBirthDate(){
birthDate = null;
}
public String getBirthDay(){
if(newDate == null){
return null;
} else {
return newDate.getDayOfWeek();
}
}
}
其他想法
那么什么时候可以复制代码/数据呢?这一部分将主要基于我的经验/观点,所以准备好不同意。
- 对于非常简单的代码(如简单的表达式),重复可能是可以接受的。只有当表达式读起来很琐碎,很难出错,并且不容易与附近的某个逻辑实体分组时,这才是正确的
- 当语言不支持抽象来消除重复时。例如,因为Java没有闭包,所以从比较器和其他"函数对象"中删除重复可能会很麻烦。因此,某些类型的重复是常见的
- 一旦遇到性能问题,可能需要进行数据复制以加快速度
- 你没有足够的时间让它"恰到好处"。这一点实际上更多的是选择你的战斗。某些类型的复制比其他类型的更危险。通常情况下,需求的变化会迫使重复进入设计良好的系统。唯一的解决方案可能很昂贵。在这种情况下,与您的团队/经理交谈并决定修复的重要性是有意义的