创造功能或不创造功能

时间:2013-01-19 01:17:49

标签: c++ coding-style

注意:对于这个问题,我将主要参考C ++,但这可能适用于其他语言。

注意:请假设没有递归。

人们经常说(如果你有一个特别大的功能)将一个功能“分解”成几个较小的功能 功能,但这是合乎逻辑的吗?如果我知道我永远不会使用其中一个较小的函数,该怎么办? 这只是浪费:内存,性能,你可能不得不在阅读时更多地跳过代码。 如果你只使用一个(假设大的)函数一次,你应该只插入 函数体进入它将被调用的地方(出于与上次相同的原因,即:内存,性能,你可能不得不在阅读时更多地跳过代码)?所以...要做一个功能或不做功能,这就是问题。

全部 * 修改 *

我仍然会经历所有的答案,但是从我到目前为止所读到的内容,我已经形成了一个假设。

在开发过程中将功能分开是否正确,但是在部署之前做了我在问题中建议的内容,以及在开发中使用一次的功能,还是在部署之前插入主体?

3 个答案:

答案 0 :(得分:1)

这实际上取决于背景。

当我们说一个函数的大小时,我们实际上是指函数内部行的语义距离。我们希望一个函数只能做一件事。如果你的函数只做了一件事,并且语义距离很小,那么可以使用大函数。

然而,将函数做很多事情并不是一个好习惯,最好将这些函数重构为一些具有良好命名和良好代码放置的较小函数,这样代码的用户就不会需要跳来跳去。

答案 1 :(得分:1)

不要过分担心性能和内存。您的编译器应该为您处理大部分内容,尤其是对于非常薄的函数。

我的目标通常是确保给定的函数调用可以在读者的内存中完全替换 - 开发人员可以纯粹地处理抽象。拿这个:

// Imagine here that these are real variable/function names as written by a
// lazy coder. I have seen code like this in the wild.
void someFunc(int arg1, int arg2) {
  int val3 = doFirstPart(arg1, field1);
  int val4 = doSecondPart(arg2, val3);
  queue.push(val4);
}

doFirstPart和doSecondPart的重构很少能为您买单,并且可能会让事情变得更难理解。这里的问题不是方法提取,而是:问题是命名和抽象不佳!您必须阅读doFirstPartdoSecondPart,否则整个功能都会丢失。

考虑一下,改为:

void pushLatestRateAndValue(int rate, int value) {
  int rateIndex = calculateRateIndex(rate, latestRateTable);
  int valueIndex = caludateValueIndex(rateIndex, value);
  queue.push(valueIndex);
}

在这个人为的例子中,除非你真的想深入挖掘,否则你不必阅读calculateRateIndexcalculateValueIndex - 你只需通过阅读它就能确切知道它的作用。

除此之外,它可能是个人风格的问题。我知道有些程序员喜欢将每个业务“声明”提取到不同的功能中,但我发现有点难以阅读。我个人的偏好是寻找机会从长于一个“屏幕”(~25行)的任何函数中提取函数,这有利于保持整个函数一次可见,并且还因为我的个人精神发生了25行短期记忆的限制和临时理解。

答案 2 :(得分:1)

有许多好的论据可以使一个例程的时间长于大致适合一页的例程。大多数人并不总是想到的一点是 - 除非你部署调试符号,大多数人都没有这样做 - 来自现场的堆栈跟踪更容易分析并变成关于原因的假设它引用的例程比错误结果发生在一个你永远不会分裂的方法的2000行鲸鱼的某处。