Temporal Coupling Between Method Calls

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

时间耦合发生在顺序方法调用之间,当它们必须保持特定顺序时。这在命令式编程中是不可避免的,但我们只需将这些静态过程转换为函数,就可以减少其负面影响。看看这个例子。

class Foo {
  public List<String> names() {
    List<String> list = new LinkedList();
    Foo.append(list, "Jeff");
    Foo.append(list, "Walter");
    return list;
  }
  private static void append(
    List<String> list, String item) {
    list.add(item.toLowerCase());
  }
}

你对此有什么看法?我认为“names ()”正在做的事情很明确——创建一个名字列表。为了避免重复,还有一个补充的procedure,“append ()”,它将项目转换为小写并将其添加到列表中。

这是一个糟糕的设计。

这是一个过程化设计,在方法“names ()”中的行之间存在时间耦合

让我首先展示给你一个更好的(虽然不是最好的!)设计,然后我会尝试解释它的好处:

一个理想的with()方法设计会创建一个新的List实例,通过addAll(list)填充它,然后再往里面add(item),最后返回。这样做完全符合不可变性,但是速度较慢。

那么,这种方法有什么问题呢:

看起来完全干净,不是吗?实例化一个列表,将两个项目添加到其中,然后返回它。是的,现在是干净的。因为我们记得append()在做什么。几个月后,我们会回到这段代码,它将会变成这样:

现在是不是很清楚 append() 实际上是将 "Jeff" 添加到 list 中了?如果我删除那行,会发生什么?会影响最后一行返回的结果吗?我不知道。我需要检查一下 append() 方法的主体来确保。

还有,先返回 list,然后再调用 append() 怎么样?这可能是我们的代码可能进行的“重构”操作。

首先,当list还没有准备好时,我们会过早地返回它。但是有人告诉我,在return list之前,这两个append()调用必须发生吗?其次,我们改变了append()调用的顺序。同样,有人告诉我按照特定的顺序调用它们很重要吗?

没有人。没有地方。这被称为时间耦合

我们的代码行耦合在一起。它们必须保持特定的顺序,但是有关这个顺序的知识是隐藏的。很容易破坏顺序,而我们的编译器将无法捕捉到我们的错误。

相反,这种设计没有任何“顺序”:

它只是返回一个列表,该列表是通过对with()方法进行几次调用构建而成的。它是一行代码,而不是四行。

如前所述,面向对象编程中的理想方法必须只有一条语句,而这条语句就是return

对于验证也是如此。例如,以下代码是不好的:

尽管这一个要好得多:

See the difference?

当然,最理想的方法是使用可组合的装饰器,而不是使用这些丑陋的静态方法。但如果由于某种原因不可能使用装饰器,就不要让这些静态方法看起来像过程。确保它们始终返回结果,并将结果作为进一步调用的参数。

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-28 at 14:50

sixnines availability badge   GitHub stars