¿Cuándo es apropiada la sobrecarga de métodos?

10

Supongamos que estoy trabajando en un sistema existente, razonablemente grande. Tengo un objeto, myObjectde clase MyClass(por el bien del ejemplo, supongamos que estoy trabajando en Java). myObjectes una composición que contiene Collection, digamos, Listay otros objetos que (creo) son irrelevantes. Contiene métodos delegados que solo sirven para invocar los métodos de los Listque está compuesto, con el fin de asegurarse de Listque no estén expuestos (lo siento si me equivoco con mi terminología).

Digamos que este Listes un List<String>pero, por alguna razón, el método de acceso principal es un método de máscara para la clase SomeOtherClass. Si quisiera insertar un nuevo par de valores en mi List, entonces tendría un objeto SomeOtherClassllamado someObject. Llamaría myObject.insert(someObject)y dentro del insertmétodo habría algo de magia que recuperaría un Stringpara poner en el List<String>.

Supongamos ahora que solo tengo un Stringvalor y ningún SomeOtherClassobjeto para insertar. Suponiendo que no puedo modificar el insertmétodo porque rompería todo en este sistema. Entonces, ¿debería sobrecargar el insertmétodo? ¿O debería crear un nuevo objeto SomeOtherClasscada vez que quiera llamar insert?

Supongo que si lo sobrecargara, se vería así ...

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

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

(Este ejemplo es un rompecabezas artificial basado en una situación similar (un poco más compleja) con respecto a la sobrecarga que encontré ayer. Lo ampliaré si hay algo que no estaba claro)

¿Sería este un lugar apropiado para sobrecargar un método? Si no, ¿cuándo debería sobrecargar un método?

blahman
fuente
Suponiendo Java, ¿ha estudiado el uso de genéricos para resolver este problema? Supongo que lo que realmente pregunto es qué representa realmente la cadena. Si en realidad es realmente una representación de un objeto de dominio real, entonces hay otra manera potencial de resolver este problema
Martijn Verburg,
@MartijnVerburg no lo he hecho, en esta etapa. Como solo soy un interno, todavía no estoy familiarizado con cosas como los patrones de diseño y todavía no tengo buenos hábitos de práctica de diseño. En respuesta a su segunda pregunta, es una representación de un objeto de dominio real. magicStringMethod()en mi ejemplo, en mi caso, obtendría una Stringrepresentación de SomeOtherObjectcuál era un objeto de dominio.
blahman
Sugiero que te mantengas alejado de la sobrecarga cuando puedas. A veces causa confusión. Es mejor estar seguro sobre el método llamado en tiempo de diseño. Vea esto: programmers.stackexchange.com/questions/132369/…
NoChance

Respuestas:

7

Se sobrecarga cuando desea admitir diferentes tipos:

public overload void MyMethod(int value)
{ 
}

public overload void MyMethod(bool value)
{
}

public overload void MyMethod(string value)
{
}

o para admitir una interfaz progresiva utilizando 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)
{
    ...
}

Incluso puede volverse un poco loco y admitir ambos tipos diferentes Y una interfaz progresiva, pero debe tener en cuenta que debe evitar crear variaciones en el comportamiento entre los métodos sobrecargados. Cada método sobrecargado debería ser funcionalmente el mismo que los demás en un grupo sobrecargado, de lo contrario no estará claro cómo, cuándo o por qué se varía el comportamiento. Si desea que dos funciones hagan algo completamente diferente, debe nombrarlas en consecuencia.

S.Robins
fuente
7

Yo diría que la sobrecarga es apropiada cuando ambos métodos son semánticamente equivalentes. Para robar de los ejemplos de dukeofgaming:

Estos están sobrecargados adecuadamente:

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

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

Estos no son:

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

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

Ese es un ejemplo extremo (si no lo captó, el último método en realidad resta en lugar de sumar), pero la idea es que si tiene varios métodos en una clase con el mismo nombre, se comporten de manera consistente.

En su ejemplo, a partir de la información dada, parecen ser equivalentes (ya que uno llama al otro) y creo que es razonable sobrecargarlos. No está de más preguntar a alguien de mayor rango en su equipo si no está seguro de si el método debe agregarse, pero si lo agrega, usaría el mismo nombre (es decir, lo sobrecargaría).

Gyan alias Gary Buyn
fuente
1
Gracias por la respuesta. Le pregunté a alguien más importante, pero dado que el código está en un estado algo interesante, su solución fue una de la que no estaba seguro, pero que sin embargo implementé (no fue la sobrecarga).
blahman
5

Esencialmente para que los parámetros del método dicten cómo se comportará el método.

Un ejemplo rápido sería:

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

Si pasa la suma del método (a, b) un par de enteros, sabe que debe llamar a la primera implementación, ya que la llamada al método coincide con la firma del método (es decir, la suma doble (doble, doble) no funcionará si proporciona método de suma dos enteros).

La firma de la llamada debe coincidir con las implementaciones disponibles, por lo que intentar llamar a sum (string, string) no funcionará a menos que tenga esto:

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 la clase maneje el método correcto de acuerdo con los parámetros que le dé a un método con el mismo nombre.

Al heredar, se llama anulación

Un buen ejemplo de este otro escenario es cuando desea alterar el comportamiento predeterminado de una clase al heredarlo, y particularmente cuando tiene algo similar al patrón de método de plantilla , donde tiene cada paso de algún algoritmo implementado en un método.

Imagina que tienes class Robotun método llamado fireAtTarget(Target target)... que se llama fireWeaponA(target); fireWeaponB(target); fireWeaponC(target);uno después del otro. También desea tener una colección llamada robot_army a la que solo puede agregar objetos de la clase Robot. El robot dispara ametralladoras por defecto en sus fireWeaponX()métodos.

Entonces usted quiere tener class LazorRoboty class MissileRobot, de implantación de los robot de nuevo ?, no, sólo hay LazorRobot y hereda MissileRobot robot, y la sobrecarga de cada fireWeaponX()método para uso lazorz o misiles y tendrá el mismo comportamiento con diferentes armas, sin tener que reimplementar El resto de los métodos.

tl; dr: para que el comportamiento del método dependa de la clase sin romper la interfaz (robot_army solo acepta Robot, pero acepta por extensión cualquier clase que herede Robot).

dukeofgaming
fuente
Su primer ejemplo es una anulación . Cuando mantiene la interfaz de un método, cambia el comportamiento en un descendiente. La implicación es que no tiene la intención de ofrecer un método alternativo. Sin embargo, su segundo ejemplo es una sobrecarga correcta. Si su intención es resaltar cuándo anular frente a cuándo sobrecargar, es posible que desee aclarar esto en su respuesta, de lo contrario when inheriting, probablemente no sea necesaria la sección completa . :)
S.Robins
Derp, la cafeína me atrapó esta vez = P, dejó la segunda parte como primera y la primera como segunda por interés general. Gracias por la corrección.
dukeofgaming
Si entiendo su respuesta correctamente, debería sobrecargarme solo cuando mirar los parámetros me permita inferir las diferencias de comportamiento entre, digamos, sum(String, String)y sum(int, int)?
blahman
@blahman deberías sobrecargar cuando desees usar diferentes tipos, una mezcla de tipos, o incluso agregar parámetros adicionales. La sobrecarga proporciona una forma de crear métodos con parámetros predeterminados donde la sintaxis predeterminada param = value no es compatible. Vea mi respuesta para ver a qué me refiero.
S.Robins
1
@blahman BTW y sobre otro tema, cuando tiene demasiados parámetros y algunos de ellos son opcionales, a veces es mejor enviar un solo objeto o estructura de datos que tenga todos los valores predeterminados, por lo que cambia los atributos de dicho objeto o datos estructura. De esa manera, no necesita hacer 20 versiones del mismo método solo para agregar un solo parámetro cada vez.
dukeofgaming