方法重载什么时候合适?


10

假设我正在开发一个现有的,相当大的系统。我有一个myObject类的对象MyClass(出于示例的原因,假设我正在Java中工作)。myObject是一种含有一种组合物Collection,比方说,一个List和其它目的(我认为)是无关紧要的。它包含委托方法,这些委托方法仅用于调用List它所组成的方法,以确保List它所具有的不暴露(对不起,如果我的术语错误)。

假设这List是一个,List<String>但是由于某种原因,主要的访问方法是class的mask方法SomeOtherClass。如果要在其中插入一个新的值对List,则需要一个SomeOtherClass名为的对象someObject。我会打电话给,myObject.insert(someObject)并且在insert方法内部将有一些魔术可以检索String到中放入List<String>

现在假设我只有一个String值,没有SomeOtherClass要插入的对象。假设我无法修改该insert方法,因为它会破坏系统中的所有内容。那我应该重载该insert方法吗?还是应该在SomeOtherClass每次调用时创建一个新对象insert

我想如果我确实超载了,它会看起来像这样……

public void insert(String s) {
    ...
}

public void insert(SomeOtherObject obj) {
    this.insert(obj.magicStringMethod());
}

(此示例是一个人为的难题,它基于我昨天遇到的关于超载的类似(稍微复杂一些)情况。如果有不清楚的地方,我将对其进行扩展)

这是重载方法的合适地方吗?如果没有,我什么时候应该重载方法?


假设使用Java,您是否考虑过使用泛型来解决此问题?我想我真正要问的是String真正代表什么?如果它实际上是实际领域对象的表示,那么还有另一种可能的方法可以解决此问题
Martijn Verburg,2012年

@MartijnVerburg在这个阶段我还没有。由于我只是一名实习生,所以我对设计模式之类的东西仍然不熟悉,并且我还没有良好的设计实践习惯。在回答第二个问题时,它是实际域对象的表示。magicStringMethod()在我的示例中,以我的示例为例,它String表示SomeOtherObject一个域对象。
blahman 2012年

我建议您尽可能避免超载。有时确实会造成混乱。在设计时最好确定调用的方法。看到这一点:programmers.stackexchange.com/questions/132369/...
NoChance

Answers:


7

当您希望支持其他类型时,您会超载:

public overload void MyMethod(int value)
{ 
}

public overload void MyMethod(bool value)
{
}

public overload void MyMethod(string value)
{
}

或支持使用不同参数列表的渐进式接口:

public overload void MyOtherMethod()
{
    this.MyOtherMethod(DefaultValue);
}

public overload void MyOtherMethod(int value)
{
    this.MyOtherMethod(value, DefaultOtherValue);
}

public overload void MyOtherMethod(int value, bool otherValue)
{
    ...
}

您甚至可能会发疯,并同时支持不同的类型和渐进式接口,但是请记住,需要避免在重载方法之间创建行为差异。每个重载方法在功能上应与重载组中的其他方法相同,否则不清楚如何,何时或为何改变行为。如果您希望两个函数做完全不同的事情,则应相应地命名它们。


7

我想说,当两种方法在语义上等效时,重载是适当的。从dukeofgaming的示例中窃取:

这些会适当地重载:

public int sum(int a, int b){
    return a+b;
}

public double sum(double a, double b){
    return a+b;
}

这些不是:

public int sum(int a, int b){
    return a+b;
}

public double sum(double a, double b){
    return a-b;
}

那是一个极端的例子(如果您没有抓住它,最后一个方法实际上是减去而不是加法),但是想法是,如果一个类中有多个同名方法,它们应该表现一致。

在您的示例中,从给定的信息来看,它们似乎是等效的(因为一个调用另一个),因此我认为重载它们是合理的。如果您不确定是否应该添加该方法,可以问问团队中其他高层人员,这很容易,但是如果您确实添加了该方法,我会使用相同的名称(即,我会重载它)。


1
感谢您的回答。我确实问过一个更高级的人,但是由于代码处于某种有趣的状态,所以我不确定他们的解决方案是什么,但是仍然可以实现(这不是重载)。
blahman 2012年

5

从本质上说,使方法的参数决定方法的行为。

一个简单的例子是:

class Calc{
    //...
    public int sum(int a, int b){
        return a+b;
    }
    public double sum(double a, double b){
        return a+b;
    }
    //...
}

如果您将方法sum(a,b)传递给几个整数,它将知道它应该调用第一个实现,因为该方法调用与方法签名一致(即,如果给定和方法两个整数)。

调用的签名必须与可用的实现匹配,因此除非您具有以下条件,否则尝试调用sum(string,string)将不起作用:

class Calc{
    //...
    public int sum(int a, int b){
        return a+b;
    }
    public double sum(double a, double b){
        return a+b;
    }
    public string sum(String a, String b){
        return "" + (Double.parseDouble(a) + Double.parseDouble(b));
    }
    //...
}

tl; dr:要让类根据给定名称相同的方法的任何参数来处理正确的方法。

继承时称为覆盖

另一种情况的一个很好的例子是,您想通过继承来改变类的默认行为,尤其是当您具有类似于模板方法模式的东西时,其中您在方法中实现了某些算法的每个步骤。

想象一下,您有class Robot一个名为fireAtTarget(Target target)... 的方法,该方法fireWeaponA(target); fireWeaponB(target); fireWeaponC(target);彼此调用。您还希望有一个名为robot_army的集合,只能向其中添加Robot类的对象。机器人默认会使用机枪射击fireWeaponX()方法。

然后,您想拥有class LazorRobotclass MissileRobot,是否又要重新实现Robot ?,不,只需让LazorRobot和MissileRobot继承Robot,并重载每种fireWeaponX()使用lazorz或导弹的方法,您将具有使用不同武器的相同行为,而无需重新实现其余方法。

tl; dr:要使方法的行为取决于类而不破坏接口(robot_army仅接受Robot,但通过扩展接受继承Robot的任何类)。


您的第一个示例是重写。当您维护方法的接口时,请更改后代中的行为。这意味着您不打算提供替代方法。但是,您的第二个示例是正确的重载。如果您打算突出何时覆盖和何时过载,则可能希望在回答中更清楚地说明这一点,否则when inheriting可能不需要整个部分。:)
S.Robins '02

Derp,咖啡因这次确实使我得到= P,出于一般兴趣,将第二部分作为第一部分,将第一部分作为第二部分。感谢您的更正。
dukeofgaming 2012年

如果我没有理解你的答案,我应该只在参数看可以让我推断之间,也就是说行为的差异时,超载,sum(String, String)sum(int, int)
blahman 2012年

@blahman,当您希望使用不同类型,混合类型甚至添加其他参数时,应重载。重载提供了一种使用默认参数创建方法的方法,其中不支持param = value默认语法。看我的答案,明白我的意思。
S.Robins'2

1
@blahman BTW以及其他主题,当您有太多参数并且其中一些参数是可选的时,有时最好只发送具有所有默认值的单个对象或数据结构,因此您可以更改此类对象或数据的属性结构体。这样,您无需每次都添加单个参数就可以制作20个版本的相同方法。
dukeofgaming 2012年
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.