Quando è appropriato il sovraccarico del metodo?


10

Supponiamo che sto lavorando su un sistema esistente, abbastanza grande. Ho un oggetto, myObjectdi classe MyClass(per esempio, supponiamo che io stia lavorando in Java). myObjectè una composizione contenente un Collection, diciamo, un Liste altri oggetti che (penso) sono irrilevanti. Contiene metodi delegati che servono solo a ricorrere ai metodi di Listcui è composto, al fine di garantire Listche non sia esposto (scusate se ho sbagliato la mia terminologia).

Diciamo che questo Listè un List<String>ma, per qualche motivo, il metodo di accesso principale è un metodo maschera per classe SomeOtherClass. Se volessi inserire una nuova coppia di valori nel mio List, allora avrei un oggetto SomeOtherClasschiamato someObject. Chiamerei myObject.insert(someObject)e all'interno del insertmetodo ci sarebbe stata qualche magia che avrebbe recuperato un Stringda mettere nel List<String>.

Supponiamo ora di avere solo un Stringvalore e nessun SomeOtherClassoggetto da inserire. Supponendo che non riesco a modificare il insertmetodo perché si romperà tutto in questo sistema. Quindi dovrei sovraccaricare il insertmetodo? O dovrei creare un nuovo oggetto SomeOtherClassogni volta che voglio chiamare insert?

Immagino che se lo sovraccaricassi, sarebbe simile a questo ...

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) per quanto riguarda il sovraccarico che ho riscontrato ieri. Lo espanderò se c'è qualcosa di poco chiaro)

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


Supponendo Java, hai esaminato l'uso di Generics per risolvere questo problema? Immagino che quello che sto davvero chiedendo sia che cosa rappresenti davvero la String? Se in realtà è davvero una rappresentazione di un vero oggetto di dominio, allora c'è un altro potenziale modo per risolvere questo problema
Martijn Verburg,

@MartijnVerburg Non ho, in questa fase. Dato che sono solo un tirocinante, non ho ancora familiarità con cose come i modelli di design e non ho ancora buone abitudini di progettazione. In risposta alla tua seconda domanda, è una rappresentazione di un oggetto di dominio reale. magicStringMethod()nel mio esempio otterrei, nel mio caso, una Stringrappresentazione di SomeOtherObjectquale era un oggetto dominio.
blahman,

Ti suggerisco di evitare il sovraccarico quando puoi. A volte causa confusione. È meglio essere certi del metodo chiamato in fase di progettazione. Guarda questo: programmers.stackexchange.com/questions/132369/…
NoChance

Risposte:


7

Si sovraccarica quando si desidera 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 entrambi i diversi tipi E un'interfaccia progressiva, ma dovresti tenere presente che devi evitare di creare variazioni nel comportamento tra metodi sovraccarichi. Ogni metodo sovraccarico dovrebbe essere funzionalmente uguale agli altri in un gruppo sovraccarico, altrimenti non sarà chiaro come, quando o perché il comportamento verrà variato. Se vuoi che due funzioni facciano qualcosa di completamente diverso, dovresti nominarle di conseguenza.


7

Direi che il sovraccarico è 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 l'hai preso, l'ultimo metodo sottrae invece di aggiungere), ma l'idea è che se hai più metodi in una classe con lo stesso nome dovrebbero comportarsi in modo coerente.

Nel tuo esempio, dalle informazioni fornite sembrano equivalenti (poiché l'una chiama l'altra) e riterrei ragionevole sovraccaricarle. Non può far male chiedere a qualcuno più anziano nella tua squadra se non sei sicuro che il metodo debba essere aggiunto, ma se lo aggiungessi userei lo stesso nome (cioè lo sovraccaricherei).


1
Grazie per la risposta. Ho chiesto a qualcuno più senior, ma dato che il codice è in uno stato un po 'interessante la loro soluzione era una di cui non ero sicuro, ma tuttavia implementato (non era il sovraccarico).
blahman,

5

Essenzialmente per avere i parametri del metodo dettare come si comporterà il 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 si passa alla somma del metodo (a, b) un paio di numeri interi, si sa che dovrebbe chiamare la prima implementazione, poiché la chiamata al metodo coincide con la firma del metodo (cioè la doppia somma (doppia, doppia) non funzionerà se si dà il somma del metodo due numeri interi).

La firma della chiamata deve corrispondere alle implementazioni disponibili, quindi provare a chiamare sum (stringa, stringa) non funzionerà a meno che tu non 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: fare in modo che la classe gestisca il metodo corretto in base a qualunque parametro si dia a un metodo con lo stesso nome.

Quando eredita, si chiama override

Un buon esempio di questo altro scenario è quando si desidera modificare il comportamento predefinito di una classe ereditandola, in particolare quando si dispone di qualcosa di simile al modello di metodo del modello, in cui è stato implementato ogni passaggio di un algoritmo in un metodo.

Immagina di avere class Robotun metodo chiamato fireAtTarget(Target target)... che si chiama fireWeaponA(target); fireWeaponB(target); fireWeaponC(target);uno dopo l'altro. Vuoi anche avere una collezione chiamata robot_army alla quale puoi aggiungere solo oggetti della classe Robot. Il robot spara mitragliatrici per impostazione predefinita nei suoi fireWeaponX()metodi.

Quindi vuoi avere class LazorRobote class MissileRobotimplementare Robot di nuovo ?, no, basta che LazorRobot e MissileRobot ereditino Robot e sovraccarichi ogni fireWeaponX()metodo per usare lazorz o missili e avrai lo stesso comportamento con armi diverse, senza dover reimplementare il resto dei metodi.

tl; dr: far sì che il comportamento del metodo dipenda dalla classe senza interrompere l'interfaccia (robot_army accetta solo Robot, ma accetta per estensione tutte le classi che ereditano Robot).


Il tuo primo esempio è una sostituzione . Quando si mantiene l'interfaccia di un metodo, si cambia il comportamento in un discendente. L'implicazione è che non si intende offrire un metodo alternativo. Il tuo secondo esempio tuttavia è correttamente sovraccarico. Se la tua intenzione è quella di evidenziare quando eseguire l'override rispetto a quando sovraccaricare, potresti voler renderlo più chiaro nella tua risposta, altrimenti l'intera when inheritingsezione probabilmente non sarà necessaria. :)
S.Robins,

Derp, questa volta la caffeina mi ha portato = P, ha lasciato la seconda parte come prima e la prima come seconda per interesse generale. Grazie per la correzione.
dukeofgaming

Se capisco correttamente la tua risposta, dovrei sovraccaricare solo quando guardo i parametri mi permetterà di dedurre le differenze di comportamento tra, diciamo, sum(String, String)e sum(int, int)?
blahman,

@blahman dovresti sovraccaricare quando desideri utilizzare tipi diversi, una combinazione di tipi o addirittura aggiungere parametri aggiuntivi. Il sovraccarico consente di creare metodi con parametri predefiniti in cui la sintassi predefinita param = value non è supportata. Vedi la mia risposta per vedere cosa intendo.
S.Robins,

1
@blahman BTW e su un altro argomento, quando hai troppi parametri e alcuni di essi sono opzionali a volte è meglio inviare un singolo oggetto o una struttura dati che ha tutti i valori predefiniti, quindi puoi cambiare gli attributi di tale oggetto o dati struttura. In questo modo non è necessario creare 20 versioni dello stesso metodo solo per aggiungere un singolo parametro ogni volta.
dukeofgaming,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.