Quando il sovraccarico del metodo è appropriato?

9

Supponiamo che io stia lavorando su un sistema esistente, ragionevolmente grande. Ho un oggetto, myObject della classe MyClass (per l'esempio, supponiamo che io stia lavorando in Java). myObject è una composizione contenente un Collection , ad esempio un List e altri oggetti che (penso) sono irrilevanti. Contiene metodi delegati che servono solo a richiamare i metodi del List di cui è composto, al fine di garantire che List non sia stato esposto (scusa se ho sbagliato la terminologia).

Diciamo che questo List è un List<String> ma, per qualche ragione, il metodo di accesso principale è un metodo di maschera per la classe SomeOtherClass . Se volessi inserire una nuova coppia di valori nel mio List , avrei un oggetto di SomeOtherClass chiamato someObject . Chiamerei myObject.insert(someObject) e all'interno del metodo insert ci sarebbe un po 'di magia che recuperi un String da inserire in List<String> .

Supponiamo ora di avere solo un valore String e nessun oggetto SomeOtherClass da inserire. Supponendo che non sia possibile modificare il metodo insert perché interromperà tutto in questo sistema. Quindi dovrei sovraccaricare il metodo insert ? O dovrei creare un nuovo oggetto di SomeOtherClass ogni volta che voglio chiamare insert ?

Suppongo che se l'ho sovraccaricato, sembrerebbe qualcosa di simile ...

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

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

(Questo esempio è un puzzle inventato basato su una situazione simile (leggermente più complessa) riguardante il sovraccarico che ho incontrato ieri. Espanderò se c'è qualcosa che non è chiaro)

Questo sarebbe un posto appropriato per sovraccaricare un metodo? In caso contrario, quando devo sovraccaricare un metodo?

    
posta blahman 16.02.2012 - 02:57
fonte

3 risposte

7

Sovraccarichi quando desideri supportare diversi tipi:

public overload void MyMethod(int value)
{ 
}

public overload void MyMethod(bool value)
{
}

public overload void MyMethod(string value)
{
}

o per supportare un'interfaccia progressiva utilizzando diversi elenchi di parametri:

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

Potresti anche diventare un po 'pazzo e supportare sia tipi diversi che un'interfaccia progressiva, ma dovresti tenere presente che è necessario evitare di creare variazioni nel comportamento tra i metodi sovraccaricati. Ogni metodo sovraccarico dovrebbe essere funzionalmente uguale agli altri in un gruppo sovraccarico, altrimenti non sarà chiaro come, quando o perché il comportamento viene variato. Se vuoi che due funzioni facciano qualcosa di completamente diverso, dovresti nominarle di conseguenza.

    
risposta data 16.02.2012 - 11:50
fonte
7

Direi che l'overloading è appropriato quando entrambi i metodi sono semanticamente equivalenti. Per rubare dagli esempi di dukeofgaming:

Questi sono sovraccaricati in modo appropriato:

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

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

Questi non sono:

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

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

Questo è un esempio estremo (se non lo prendi, l'ultimo metodo in realtà sottrae invece di add), ma l'idea è che se hai più metodi in una classe con lo stesso nome, dovrebbero comportarsi in modo coerente. / p>

Nel tuo esempio, dalle informazioni fornite sembrano equivalenti (dal momento che si chiama l'altro) e penso che sia ragionevole sovraccaricarle. Non può fare male chiedere a qualcuno più anziano della tua squadra se non sei sicuro se il metodo debba essere aggiunto, ma se lo hai aggiunto userei lo stesso nome (cioè lo sovraccarico).

    
risposta data 16.02.2012 - 05:42
fonte
5

Essenzialmente per avere i parametri del metodo che determinano il comportamento del metodo.

Un rapido esempio potrebbe essere:

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

Se passi il metodo sum (a, b) un paio di interi sa che dovrebbe chiamare la prima implementazione, poiché la chiamata al metodo coincide con la firma del metodo (cioè la doppia somma (double, double) non funzionerà se fornisci il metodo sum a due interi).

La firma della chiamata deve corrispondere alle implementazioni disponibili, quindi provare a chiamare sum (string, string) non funzionerà a meno che non si abbia questo:

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: per fare in modo che la classe gestisca il metodo corretto in base a qualunque parametro tu fornisca un metodo con lo stesso nome.

Quando si eredita, è chiamato overriding

Un buon esempio di questo altro scenario è quando si desidera modificare il comportamento predefinito di una classe ereditandola, in particolare quando si ha qualcosa di simile a modello metodo , in cui ogni passo di un algoritmo è implementato in un metodo.

Immagina di avere class Robot e un metodo chiamato fireAtTarget(Target target) ... che chiama fireWeaponA(target); fireWeaponB(target); fireWeaponC(target); uno dopo l'altro. Vuoi anche avere una collezione chiamata robot_army a cui puoi solo aggiungere oggetti della classe Robot. Il robot spara mitragliatrici di default nei suoi metodi fireWeaponX() .

Allora vuoi avere class LazorRobot e class MissileRobot , implementa nuovamente Robot ?, no, solo LazorRobot e MissileRobot ereditano Robot e overload ogni fireWeaponX() metodo a usa lazorz o missili e avrai lo stesso comportamento con armi diverse, senza dover reimplementare il resto dei metodi.

tl; dr: Per fare in modo che il comportamento del metodo dipenda dalla classe senza interrompere l'interfaccia (robot_army accetta solo Robot, ma accetta per estensione qualsiasi classe che eredita Robot).

    
risposta data 16.02.2012 - 04:32
fonte