我们应该重命名重载的方法吗?


14

假定包含以下方法的接口:

Car find(long id);

List<Car> find(String model);

像这样重命名它们更好吗?

Car findById(long id);

List findByModel(String model);

实际上,使用此API的任何开发人员都无需查看接口即可知道初始find()方法的可能参数。

所以我的问题更笼统:在代码中使用重载方法有什么好处,因为它会降低可读性?


4
只要您保持一致,任何一种方法都是可以接受的。
克里斯·夫(CheF)

重载和覆盖方法之间存在关系。但是这篇文章有利于你的建议-这可能会感兴趣:roseindia.net/javatutorials/...
NoChance

Answers:


23

与您可能会遇到的许多其他不良可读性实践相比,这是一个相对较小的问题,因此我想说,如何命名方法主要取决于口味。

话虽如此,如果您要对此做点什么,我将遵循以下做法:

  • 如果...超载

    这些方法几乎遵循相同的合同,但仅在不同的输入上操作(想象一个电话接线员可以通过您的个人税号,您的帐号或您的姓名和生日查询您的帐户)。这包括返回相同类型的输出

  • 如果使用其他名称...

    这些方法做的事情大不相同,或者返回不同的输出(例如您的情况)。如果一个人访问数据库而另一个人不访问数据库,则可以考虑使用其他名称。

    另外,如果返回的类型不同,我还将更改动词以表明:

    Car findById(long id);
    
    List findAllByModel(String model);
    

3
FWIW,我会说得更强烈一点:“这些方法遵循完全相同的约定……”也就是说,参数类型/计数无关紧要-函数调用的语义相同。如果参数类型/计数很重要,那么您不应该重载。
mcmcc 2012年

4

在每种情况下,我建议使用其他名称。这有可能是在未来的一段时间,你会希望添加其他的方法,比如List<Car> findByMake(String make),对比List<Car> findByModel(String model)。所以突然间,一切都find变得毫无意义了。如果您的方法名称提供了有关应如何使用它们的更多信息,则也不太可能无意中使用了错误的方法。


1
公平地说,如果功能由object:find(Make val)和显式表示,那么这将不成问题find(Model val)。然后,诸如此类的便捷方法findByMake(String val)将更加清楚其实际功能。毕竟,a String既不是品牌,也不是模型,因此该方法应解释其实际作用。
妮可

4

如果重命名方法,它将不再重载。就其本身而言,重载并不一定会使代码的可读性降低,但是如果语法不明确,重载可能会使实现更难以遵循。

许多语言都使用方法重载来表示功能接口的功能,其中参数可能是可选的,并且隐含了可选参数的默认值。对于在方法声明中不支持默认参数语法的语言,尤其如此。

这样做:

void MyMethod(int param1, int param2 = 10)
{
    ...
}

避免您这样做:

void MyMethod(int param1)
{
    MyMethod(param1, Param2Default);
}

void MyMethod(int param1, int param2)
{
    ....
}

至于哪个更具可读性,那实际上取决于您。我个人更喜欢第二种选择,特别是在参数列表过长的时候,但是我想只要您在整个API中保持一致就没有关系。

当您希望函数执行基本相同的操作,并且希望参数列表相同但返回类型不同时,重载就会遇到困难。大多数语言不知道如何区分两个相同但返回类型不同的方法。此时,您需要考虑使用泛型,更改参数接口或重命名其中一种方法以指示返回类型的差异。如果您不希望采用简单明了的命名方案来处理此类情况,那么可读性就可能成为一个大问题。

命名重载的方法GetSomething()GetSomethingEx()并不会过多地说明方法之间的区别,特别是如果返回类型是它们之间的唯一区别时。另一方面,GetSomethingAsInt()GetSomethingAsString()告诉您更多有关方法在做什么的信息,尽管这并不是严格意义上的重载,但它确实表明这两种方法执行相似的操作,但是返回不同的值类型。我知道您可以使用其他方法命名方法,但是为了说明这一点,这些粗略的示例应该可以做到。

在OP的示例中,重命名并不是严格必需的,因为方法参数不同,但是确实可以更清楚地命名一个方法。最后,它实际上取决于您希望提供给用户的界面类型。是否不超载的决定不应仅基于您自己对可读性的理解。重载方法可以例如简化API接口并减少开发人员可能需要记住的方法数量,另一方面,它可以使接口模糊不清,从而需要开发人员阅读方法文档以了解哪种格式。使用方法,而拥有许多类似但描述性地命名的方法,则可以使方法更加清晰,只需阅读方法名称即可。


0

只要方法返回相同的内容并遵循相同的约定,就支持重载。重载使调用代码免于不必要地提交给参数类型。

假设调用函数接收搜索查询作为参数,并在调用之前和/或之后执行其他一些处理find

void tryToSellCars(String which) {
    /* grab an airhorn, inflatable tube guy... */
    List<Car> cars = find(which);
    /* expound virtues of each car in detail... */
}

如果您出于某种原因要更改查询的类型(例如,从简单的ID字符串更改为某种功能齐全的查询对象),则只需更改函数签名即可在调用函数中进行更改接受新的参数类型,而不必担心更改它在您的类上调用的方法。

void tryToSellCar(CarQuery which) {
    /* grab airhorn, inflate tube guy... */
    List<Car> cars = find(which)
    /* expound virtues of each car in detail... */
}

如果单独实施findByIdfindByQueryObject则必须查找每个调用以进行更改。在示例中,我只更改了一个字就完成了。


当然,此答案假定您使用的语言支持对无效参数进行编译时错误的重载。如果您正在编写JavaScript或Ruby或任何其他本机不支持重载的语言,我将始终使用冗长的语句来findByFoo更早地捕获类型不匹配。
sqykly 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.