当KISS和DRY碰撞时

hel*_*hod 16 java dry

我是DRYKISS原则的追随者,但上周我有一个案例,两者似乎互相矛盾:

对于我正在做的应用程序,我必须实现一个循环,执行以下操作:

  1. 迭代类型A列表的元素
  2. 将类型A的元素转换为类型B并将它们插入到类型B的列表中

这是一个例子:

for (A a : listOfA) {
    listOfB.add(BFactory.convertFromAToB(a));
}
Run Code Online (Sandbox Code Playgroud)

在代码中,我必须做大约4次,将类型(例如D,E等)转换为另一种类型.我可能无法更改我要转换的类型,因为它们是我们必须在app中使用的第三方类型.

所以我们有:

for (A a : listOfA) {
    listOfB.add(BFactory.convertFromAToB(a));
}

for (C a : listOfC) {
    listOfB.add(DFactory.convertFromCToD(c));
}

...
Run Code Online (Sandbox Code Playgroud)

所以,为了不违反干,我提出了一个通用的解决方案:

private interface Function<S, T> {
  T apply(S s);
}

public <S, T> void convertAndCopy(List<S> src, List<T> dst, Function<S, T> f) {
    for (S s : src) {
      dst.add(f.apply(s));
    }
}
Run Code Online (Sandbox Code Playgroud)

电话看起来像这样:

convertAndCopy(listOfA, listOfB, new Function<A, B>() {
    A apply(B b) {
        return CFactory.convertFromBToC(b);
    }
});
Run Code Online (Sandbox Code Playgroud)

现在,虽然这是在干燥的条件更好,我认为它违反KISS,因为这种解决方案更难使用比复制的for循环理解.

那么,这是DRY vs. KISS吗?在这种背景下哪一个受到青睐?

编辑

为了清楚起见,我正在谈论的类是一个适配器,它将调用遗留系统委托给我们自己的实现,并将遗产转换为我们自己的类型.我无法更改遗留类型,也无法更改我们的类型(XML-Schema生成).

Thi*_*ilo 15

要么没事.

对于循环,你并没有真正重复自己,因为唯一重复的部分是"语法混乱"(在你的情况下并不是太多).您不是在重复/复制"应用程序逻辑"代码.

如果您喜欢"函数"样式,可以使用Guava库(它具有Function接口和许多在集合上使用它们的辅助方法).那是DRY(因为你不重复自己,并重新使用已经存在的代码),并且仍然是KISS(因为那些是很好理解的模式).


Juk*_*bom 12

如果您只需要在整个应用程序中执行此操作4次,并且转换实际上与示例相同,我会选择在通用解决方案上随时编写4 for循环.

可读性因使用该通用解决方案而受到很大影响,而您实际上并没有从中获得任何东西.

  • 在这种情况下,你没有从DRY获得如此多的收益:你没有主要的代码分解; 通过重复自己,你可能不会有不连贯的行为.你仍然很重复自己,因为你必须一直写"new Function <X,Y> {X apply(Y y){return CFactory.convertFromYToX(y);}}".我这次吻了. (4认同)

Ste*_*n C 10

像DRY和KISS这样的一般原则从来不会起作用.

IMO,答案是忘记教条(至少对于这个问题),并考虑什么为您提供最好/最可读的解决方案.

如果重复的x 4代码更容易理解而不是维护负担("你需要经常更改它"),它是正确的解决方案.

(Thilo的答案也是对的...... IMO)