我在这里做了一些搜索,并没有发现任何类似的东西,所以我要继续问问。这实际上更多地是关于语义而不是实际的编程问题。我目前正在用C ++编写一些东西,但语言并不重要。
我很清楚,保持您的功能/方法尽可能短是一种很好的编程习惯。然而,你怎么知道函数是否太长?或者,是否有可能将功能分解太多?
我学到的第一种编程语言(除了Applesoft BASIC,不计算......)是6502汇编语言,其中速度和优化就是一切。如果一些循环计数会搞砸整个程序的时间,通常最好直接设置内存位置或寄存器,而不是跳转到另一个子程序。前一种操作可能需要3到4个周期,而后者可能需要两到三次。
虽然我意识到现在如果我甚至向某些程序员提及循环计数,他们只是给我一个空白的外观,这是一个很难打破的习惯。
具体来说,让我们说(再次使用C ++)我们有一个私有类方法,如下所示:
int Foo::do_stuff(int x) {
this->x = x;
// various other operations on x
this->y = this->x;
}
我见过一些论据,至少,每组操作都应该是它自己的功能。例如,do_stuff()理论上应该被命名为set_x(int x),应该为在类成员x上执行的操作集编写一个单独的函数,并且应该编写第三个函数来分配类成员的最终值。 x到班级成员y。但我已经看到其他论点,即每个操作都应该有自己的功能。
对我而言,这似乎是错误的。我再一次从内部角度看问题;每个方法调用都在推送堆栈上的地址,执行其操作,然后从子例程返回。对于相对简单的事情来说,这似乎是一个很大的开销。
对于这类事情是否有最佳做法,还是更多取决于个人判断?
答案 0 :(得分:8)
自6502汇编以来,发生了两件事:计算机速度更快,编译器(适当时)变得更聪明。
现在的建议是停止花费你所有的时间来讨论个别周期,,直到你确定它是一个问题。你可以更明智地度过那段时间。如果你向我提及周期盘点,我不会茫然地看着你,因为我不知道它们是什么。我会看着你想知道你是否在浪费你的努力。
相反,开始考虑让你的功能足够小,以便:
如果稍后您发现某些代码运行速度不够快,请考虑如何对其进行优化。
注意:优化可能是提示编译器内联移动函数,因此您仍然可以获得上述优势,而不会影响性能。
答案 1 :(得分:5)
决定分解函数的位置最重要的不一定是函数执行的程度。而不是确定你班级的API。
假设我们将Foo::do_stuff
分为Foo::set_x
,Foo::twiddle_x
和Foo::set_y
。单独进行这些操作是否有意义?如果我在没有先设置它的情况下旋转x
,会发生什么不好的事吗?我可以在不致电set_y
的情况下致电set_x
吗?通过将它们分解为单独的方法,甚至是同一类中的私有方法,您暗示它们至少是潜在的单独操作。
如果情况并非如此,那么一定要将它们保存在一个功能中。
答案 2 :(得分:3)
我很清楚这很好 编程实践,以保持你的 功能/方法尽可能短
我不会使用上述标准将我的函数重构为较小的函数。以下是我使用的内容
其他good practices for Method Design
答案 3 :(得分:2)
在阅读了Clean Code: A Handbook of Agile Software Craftsmanship之后,我开始写这篇文章的几乎所有建议。不是为了具有简短的功能,而是为了提高可读性和可测试性,将它们保持在相同的抽象级别,让它们只做一件事等等。
我发现最有价值的是我发现自己编写的文档少得多,因为80%的函数不需要它。当函数只是它的名字所说的那样时,没有必要重述明显的。编写测试也变得更容易,因为每个测试方法可以设置更少并且执行更少的断言。当我重新审视过去六个月中编写这些目标的代码时,我可以更快地做出我想要的改变并继续前进。
答案 4 :(得分:0)
我认为在任何代码库中,可读性远远超过几个时钟周期,因为所有众所周知的原因,最重要的是可维护性,这是大多数代码花费时间的地方,因此大多数资金都是花在代码上。所以我有点躲避你的问题,说人们不关心它,因为它与其他[更公司]的担忧相比可以忽略不计。
虽然如果我们把其他问题放在一边,但是有明确的内联语句,更重要的是,编译器优化通常可以消除涉及普通函数调用的大部分开销。编译器是一个非常智能的优化机器,并且通常会比我们更智能地组织函数调用。