我们是将DRY原理仅应用于对象的状态,还是也应用于其行为



我很难理解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没有闭包,所以从比较器和其他"函数对象"中删除重复可能会很麻烦。因此,某些类型的重复是常见的
  • 一旦遇到性能问题,可能需要进行数据复制以加快速度
  • 你没有足够的时间让它"恰到好处"。这一点实际上更多的是选择你的战斗。某些类型的复制比其他类型的更危险。通常情况下,需求的变化会迫使重复进入设计良好的系统。唯一的解决方案可能很昂贵。在这种情况下,与您的团队/经理交谈并决定修复的重要性是有意义的

最新更新