I.23: Keep the number of function arguments low(尽量不增加函数的参数个数)

Reason(原因)

Having many arguments opens opportunities for confusion. Passing lots of arguments is often costly compared to alternatives.

参数过多会增加混淆的可能性。和其他方式相比,传递很多参数的代价通常也很高。

Discussion(讨论)

The two most common reasons why functions have too many parameters are:

函数参数过多通常有两个原因:

  1. Missing an abstraction.There is an abstraction missing, so that a compound value is being passed as individual elements instead of as a single object that enforces an invariant. This not only expands the parameter list, but it leads to errors because the component values are no longer protected by an enforced invariant.
    抽象缺失。这里缺少一个抽象,因此组合数据被分开传递而不是作为包含不变量的单独的对象。这不是扩展参数列表的问题,而是由于组合值不被强制不变量保护而引发错误的问题。
  2. Violating "one function, one responsibility."The function is trying to do more than one job and should probably be refactored.
    违反了“一个函数,一个职责”原则。函数试图做一件以上的事情,应该被重构。

Example(示例)

The standard-library ​​merge()​​ is at the limit of what we can comfortably handle:

标注库merge()就处在我们可以舒服地处理的上限:

 

template<class InputIterator1, class InputIterator2, class OutputIterator, class Compare>OutputIterator merge(InputIterator1 first1, InputIterator1 last1,                     InputIterator2 first2, InputIterator2 last2,                     OutputIterator result, Compare comp);


 


Note that this is because of problem 1 above -- missing abstraction. Instead of passing a range (abstraction), STL passed iterator pairs (unencapsulated component values).

注意这是因为前面提到的第一个问题:抽象缺失。STL传递了迭代器对(没有包装的组合值)而不是range(抽象)。

译者注:range是C++14引入的新特性。译者注:range是C++14引入的新特性。

Here, we have four template arguments and six function arguments. To simplify the most frequent and simplest uses, the comparison argument can be defaulted to ​​<​​:

这里一共有四个模板参数和六个函数参数。为了简化最常见和最简单的用法,比较操作可以默认为<(小于号):


 


 

template<class InputIterator1, class InputIterator2, class OutputIterator>OutputIterator merge(InputIterator1 first1, InputIterator1 last1,                     InputIterator2 first2, InputIterator2 last2,                     OutputIterator result);

This doesn't reduce the total complexity, but it reduces the surface complexity presented to many users. To really reduce the number of arguments, we need to bundle the arguments into higher-level abstractions:

这并没有减少复杂性,但是降低了面向很多用户的表面上的复杂度。为了真正减少参数的数量,我们需要将参数绑定到高级别的抽象中。


 


 

template<class InputRange1, class InputRange2, class OutputIterator>OutputIterator merge(InputRange1 r1, InputRange2 r2, OutputIterator result);

Grouping arguments into "bundles" is a general technique to reduce the number of arguments and to increase the opportunities for checking.

将参数分组打包是一种减少参数数量的通常技术,这样也可以增加检查的机会。

Alternatively, we could use concepts (as defined by the ISO TS) to define the notion of three types that must be usable for merging:

或者,我们也可以使用concept( 在ISO技术规范中定义)来定义合并操作必须可用的三个类型。

译者注:concept将会被C++20正式引入。


 


 

Mergeable{In1, In2, Out}OutputIterator merge(In1 r1, In2 r2, Out result);


 


Example(示例)

The safety Profiles recommend replacing

安全规则群组推荐将

 

void f(int* some_ints, int some_ints_length);  // BAD: C style, unsafe

with(替换为)

 

void f(gsl::span<int> some_ints);              // GOOD: safe, bounds-checked

Here, using an abstraction has safety and robustness benefits, and naturally also reduces the number of parameters.

这里,我们使用一个安全而且健壮的抽象,而且通常也可以减少参数的数量。

Note(注意)

How many parameters are too many? Try to use fewer than four (4) parameters. There are functions that are best expressed with four individual parameters, but not many.

多少参数算太多?争取让参数的个数少于4个。存在一些4个独立参数是最佳表达方式的函数,但不多。

Alternative: Use better abstraction: Group arguments into meaningful objects and pass the objects (by value or by reference).

可选项:使用较好的抽象:将参数分组并形成有意义的对象然后传递它(传值或传址)。

Alternative: Use default arguments or overloads to allow the most common forms of calls to be done with fewer arguments.

可选项:使用默然参数或重载以便更加通用的调用形式可以使用较少的参数。

Enforcement(实施建议)

  • Warn when a function declares two iterators (including pointers) of the same type instead of a range or a view.
    如果函数定义了相同类型的两个迭代器(包括指针)而不是range或view。
  • (Not enforceable) This is a philosophical guideline that is infeasible to check directly.

       (非强制)这是一个事关编程哲学的准则,无法直接检查。

 


阅读更多更新文章,请关注微信公众号【面向对象思考】