Quando a sobrecarga de método é apropriada?

10

Suponha que eu esteja trabalhando em um sistema razoavelmente grande existente. Eu tenho um objeto myObjectde classe MyClass(pelo exemplo, suponha que eu esteja trabalhando em Java). myObjecté uma composição que contém Collection, digamos, a, Liste outros objetos que (acho) são irrelevantes. Ele contém métodos delegados que servem apenas para invocar os métodos dos Listquais é composto, a fim de garantir que Listele não seja exposto (desculpe se minha terminologia está incorreta).

Digamos que este Listseja um List<String>método, mas, por algum motivo, o principal acesso é um método de máscara para classe SomeOtherClass. Se eu quisesse inserir um novo par de valores no meu List, teria um objeto SomeOtherClasschamado someObject. Eu chamaria myObject.insert(someObject)e dentro do insertmétodo haveria alguma mágica que recuperaria um Stringpara colocar no List<String>.

Supondo agora que eu tenha apenas um Stringvalor e nenhum SomeOtherClassobjeto para inserir. Supondo que não posso modificar o insertmétodo, porque isso quebraria tudo neste sistema. Então devo sobrecarregar o insertmétodo? Ou devo criar um novo objeto SomeOtherClasstoda vez que quiser ligar insert?

Eu acho que se eu sobrecarregasse, seria algo assim ...

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

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

(Este exemplo é um quebra-cabeça artificial baseado em uma situação semelhante (um pouco mais complexa) em relação à sobrecarga que encontrei ontem. Expandirei se houver algo que não esteja claro.

Este seria um local apropriado para sobrecarregar um método? Caso contrário, quando devo sobrecarregar um método?

blahman
fonte
Supondo que Java, você já pensou em usar os Genéricos para resolver esse problema? Acho que o que realmente estou perguntando é o que a String realmente representa? Se é realmente muito uma representação de um objeto de domínio real, então não há outra maneira potencial para resolver este problema
Martijn Verburg
@MartijnVerburg Eu não tenho, nesta fase. Como sou apenas estagiário, ainda não estou familiarizado com coisas como padrões de design e ainda não tenho bons hábitos de prática de design. Em resposta à sua segunda pergunta, é uma representação de um objeto de domínio real. magicStringMethod()no meu exemplo, no meu caso, obteria uma Stringrepresentação do SomeOtherObjectque era um objeto de domínio.
blahman
Eu sugiro que você fique longe de sobrecarregar quando puder. Às vezes, causa confusão. É melhor ter certeza sobre o método chamado em tempo de design. Veja isto: programmers.stackexchange.com/questions/132369/…
NoChance

Respostas:

7

Você sobrecarrega quando deseja oferecer suporte a diferentes tipos:

public overload void MyMethod(int value)
{ 
}

public overload void MyMethod(bool value)
{
}

public overload void MyMethod(string value)
{
}

ou para suportar uma interface progressiva usando diferentes listas de parâmetros:

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)
{
    ...
}

Você pode até ficar um pouco louco e suportar os dois tipos diferentes E uma interface progressiva, mas lembre-se de que precisa evitar criar variações de comportamento entre métodos sobrecarregados. Cada método sobrecarregado deve ser funcionalmente o mesmo que os outros em um grupo sobrecarregado; caso contrário, não ficará claro como, quando ou por que o comportamento está sendo variado. Se você deseja que duas funções façam algo completamente diferente, deve nomeá-las de acordo.

S.Robins
fonte
7

Eu diria que a sobrecarga é apropriada quando os dois métodos são semanticamente equivalentes. Para roubar dos exemplos de dukeofgaming:

Estes são sobrecarregados adequadamente:

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

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

Estes não são:

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

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

Este é um exemplo extremo (se você não o pegou, o último método subtrai em vez de adiciona), mas a idéia é que, se você tiver vários métodos em uma classe com o mesmo nome, eles deverão se comportar de maneira consistente.

No seu exemplo, pelas informações fornecidas, elas parecem equivalentes (já que uma chama a outra) e eu consideraria razoável sobrecarregá-las. Não é demais perguntar a alguém mais graduado da sua equipe se você não tem certeza se o método deve ser adicionado, mas se você o adicionasse eu usaria o mesmo nome (ou seja, eu o sobrecarregaria).

Gyan tcp Gary Buyn
fonte
11
Obrigado pela resposta. Eu perguntei a alguém mais experiente, mas como o código está em um estado um tanto interessante, a solução deles não era certa, mas, no entanto, foi implementada (não foi a sobrecarga).
blahman
5

Essencialmente, para que os parâmetros do método determinem como o método se comportará.

Um exemplo rápido seria:

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

Se você passar a soma do método (a, b) alguns inteiros, ele sabe que deve chamar a primeira implementação, pois a chamada do método coincide com a assinatura do método (ou seja, soma dupla (dupla, dupla) não funcionará se você fornecer o parâmetro soma método dois inteiros).

A assinatura da chamada deve corresponder às implementações disponíveis, portanto, tentar chamar sum (string, string) não funcionará, a menos que você tenha o seguinte:

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: Para que a classe lide com o método correto de acordo com os parâmetros que você atribuir a um método com o mesmo nome.

Ao herdar, é chamado de substituição

Um bom exemplo desse outro cenário é quando você deseja alterar o comportamento padrão de uma classe herdando-o e, particularmente, quando você tem algo semelhante ao padrão do método de modelo, em que cada etapa de algum algoritmo é implementada em um método.

Imagine que você possui class Robotum método chamado fireAtTarget(Target target)... que chama fireWeaponA(target); fireWeaponB(target); fireWeaponC(target);um após o outro. Você também deseja ter uma coleção chamada robot_army à qual você pode adicionar apenas objetos da classe Robot. O robô dispara metralhadoras por padrão em seus fireWeaponX()métodos.

Então você quer ter class LazorRobote class MissileRobotimplementa o Robot novamente ?, não, apenas LazorRobot e MissileRobot herdam o Robot e sobrecarregam cada fireWeaponX()método para usar lazorz ou mísseis e você terá o mesmo comportamento com armas diferentes, sem precisar reimplementar o restante dos métodos.

tl; dr: Para que o comportamento do método dependa da classe sem interromper a interface (robot_army aceita apenas o Robot, mas aceita por extensão todas as classes que herdam o Robot).

dukeofgaming
fonte
Seu primeiro exemplo é uma substituição . Quando você mantém a interface de um método, altera o comportamento de um descendente. A implicação é que você não pretende oferecer um método alternativo. Seu segundo exemplo, no entanto, está sobrecarregando corretamente. Se sua intenção é destacar quando substituir ou quando sobrecarregar, convém deixar isso mais claro na sua resposta, caso contrário when inheriting, provavelmente não será necessária a seção inteira . :)
S.Robins
Derp, a cafeína me pegou dessa vez = P, deixou a segunda parte como a primeira e a primeira como a segunda para interesse geral. Obrigado pela correção.
Dukeofgaming 16/02/12
Se entendi sua resposta corretamente, só deveria estar sobrecarregado ao observar os parâmetros que me permitem inferir as diferenças de comportamento entre, digamos, sum(String, String)e sum(int, int)?
blahman
@ blahman, você deve sobrecarregar quando desejar usar tipos diferentes, uma mistura de tipos ou até mesmo adicionar parâmetros adicionais. A sobrecarga fornece uma maneira de criar métodos com parâmetros padrão nos quais a sintaxe padrão param = value não é suportada. Veja minha resposta para ver o que quero dizer.
31412 S.Robins
11
@blahman BTW e em outro assunto, quando você tem muitos parâmetros e alguns deles são opcionais, às vezes é melhor enviar apenas um único objeto ou estrutura de dados que possua todos os valores padrão, para que você altere os atributos desse objeto ou dados estrutura. Dessa forma, você não precisa criar 20 versões do mesmo método apenas para adicionar um único parâmetro a cada vez.
Dukeofgaming