将公共成员函数分解为许多私有成员函数

4

当我编写一个类的公共成员函数,它可以执行多个操作时,例如...

void Level::RunLogic(...);

在该函数中,我发现自己需要将其拆分为多个私有成员函数。将公共成员函数拆分为多个函数是没有意义的,因为您不会单独执行某个操作,而且我不希望用户担心按什么顺序进行操作等问题。相反,RunLogic()函数可能如下所示...

void Level::RunLogic(...) {
 DoFirstThing();
 DoSecondThing();
 DoThirdThing();
}

在Code Complete中,Steve McConnel建议减少类中函数的数量,但我不想把所有代码都放入一个函数中,因为DoThing函数是私有成员函数。我的理解是类不应该有过多的功能,但我想知道其他程序员对此的看法。

此外,我越来越倾向于在公共成员函数中暴露更少的实现细节,并将大部分工作移动到小型私有成员函数中。显然,这会创建更多的函数...但问题就在这里。

7个回答

2

你希望保持公共方法简单,将其功能分成多个私有方法,这是正确的。

麦康奈尔认为您应该减少类中保留的方法数量,这也是正确的。

这两个目标并不矛盾。我认为麦康奈尔不会建议您延长函数长度以减少函数数目。相反,您应该考虑将其中一些私有方法推入一个或多个实用程序类中,以供公共类使用。

当然,实现最佳方式将取决于您代码的细节。


1
我建议将它们拆分成独立的方法,每个方法负责一个小任务,并为每个私有方法编写描述性的注释。将方法拆分和命名可以使逻辑代码更可读!比较一下:
double average(double[] numbers) {
  double sum = 0;
  for (double n : numbers) {
    sum += n;
  }
  return sum / numbers.length;
}

to:

double sum(double[] numbers) {
  double sum = 0;
  for (double n : numbers) sum += n;
  return sum;
}

double average(double[] numbers) {
    return sum(numbers) / numbers.length;
}

《代码大全》关注的是每个类所暴露出来的接口,而不是实现细节。

将那些较小的方法设置为包可见可能更有意义,这样你就可以轻松地对它们进行单元测试,而不仅仅是测试复杂的 RunLogic 方法。


实际上,我发现你的第一个例子更易读。循环读取所需的工作量较少。我可以管理四个语句并排。 - Tom Hawtin - tackline

1

我同意拆分功能。

我一直被教导并坚持认为,一个函数被定义为执行单个封装任务,如果它似乎做了不止一件事,则可以重构它。然后使用类将类似或相关的函数封装在一起。

将这些任务分解并仍然使用单个公共成员,在我看来,允许类以其预期的方式执行该重要任务,同时使其更易于维护。我还经常发现,在同一复杂方法中存在多个相似的代码段,可以将它们重构为具有参数的单个通用函数 - 既提高可读性和可维护性,甚至减少代码量。


0

我使用的一个规则是三原则。如果我在不同的地方做了三次相同的事情,那么值得有一个单独的(可能是私有的)成员函数来封装共享行为。

在这种情况下,我通常使用的唯一另一个规则是可读性。如果我在我的IDE中查看的成员函数填满了一个以上的屏幕,我会发现很难跟踪所有的代码路径和可能的错误转折点。在这种情况下,将一个庞大的成员函数分解为两个或更多的私有辅助函数是完全合理的。

关于Code Complete对类中函数数量的评论,记住,与函数数量相关的最大风险主要与外部可用接口的复杂性有关。您提供给其他人使用的入口点越多,出现问题的可能性就越大(例如,由于公共成员中的错误输入等导致的错误)。添加一个私有成员函数不会增加公共API的复杂性。


0

你无意中遵循了以下规则:

A class should have only one reason to change / Single responsibility principle

这是一件好事。 通过正确分离职责,您可以确保您的应用程序不会因为变更而轻易崩溃。


0

我不认为保持公共成员函数尤其是代码行数尽可能小有什么优势。通常,长函数往往不易阅读,因此在大多数情况下,将大函数的实现分散开来可以提高可读性,无论它们是否是类的一部分。

至于尽可能保持类的大小的好建议,这对于接口的公共部分和封装的数据量尤其重要。原因是具有大量数据成员和公共函数的类会撤销数据封装的优势。


0
我使用的一个“经验法则”是,任何一个函数一次不会占用超过一个屏幕的空间。虽然这种方法相对简单,但当你可以一次性“看到所有内容”时,它确实有所帮助。这也将限制(根据定义)任何一个方法的复杂性。当你需要将工作交给同事进行进一步的维护、升级和修复错误时,保持简单是很好的选择。考虑到这一点,我认为保持公共方法简单几乎总是正确的选择。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接