当KISS和DRY碰撞时[关闭]

问题描述 投票:16回答:5

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

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

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

这是一个例子:

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

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

所以我们有:

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

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

...

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

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));
    }
}

电话看起来像这样:

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

现在,虽然这在DRY方面更好,但我认为它违反了KISS,因为这个解决方案比重复的for循环更难理解。

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

编辑

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

java dry
5个回答
15
投票

要么没事。

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

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


12
投票

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

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


10
投票

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

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

如果复制的x 4代码更容易理解并且不是维护负担(即您不需要对其进行大量更改),那么这是正确的解决方案。

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


4
投票

我认为不是KISS和DRY相互矛盾。我宁愿说Java不允许你表达简单而不重复自己。

首先,如果你引入正确命名的方法,从List<A>转换为List<B>等等,而不是一直重复循环,它仍然是DRY,同时仍然保持KISS。

但我建议的是看看替代语言,这些语言可以让你充分利用DRY,同时仍然可以推广KISS,例如:在斯卡拉:

val listOfB = listOfA map convertAtoB
val listOfC = listOfB map convertBtoC
val listOfD = listOfC map convertCtoD

其中convertAtoB是一个采用A类项目并返回B的函数:

def convertAtoB(a: A): B = //...

或者你甚至可以链接这些map电话。


4
投票

您可以将转换函数移动到CFactory中:

convertAndCopy(listOfA, listOfB, CFactory.getConverterFromAToB());

代码以这种方式可读/简单,您可以促进代码重用(可能稍后需要在另一个上下文中使用转换器对象)。

实施:

public <S, T> void convertAndCopy(List<A> listofA, List<B> listOfB, Function<A, B> f) {
  listOfB.addAll(Collections2.transform(listOfA,f));
}

(使用番石榴迭代器)。

我甚至不确定你应该在这里干,你可以直接使用:

listOfB.addAll(Collections2.transform(listOfA,CFactory.getConverterFromAToB()));
© www.soinside.com 2019 - 2024. All rights reserved.