Dovremmo rinominare metodi sovraccarichi?


14

Supponi un'interfaccia contenente questi metodi:

Car find(long id);

List<Car> find(String model);

È meglio rinominarli in questo modo?

Car findById(long id);

List findByModel(String model);

In effetti, qualsiasi sviluppatore che utilizza questa API non dovrà guardare l'interfaccia per conoscere i possibili argomenti dei find()metodi iniziali .

Quindi la mia domanda è più generale: quali sono i vantaggi dell'utilizzo di metodi sovraccarichi nel codice poiché riduce la leggibilità?


4
Entrambi i metodi sono accettabili purché siano coerenti.
ChrisF

Esiste una relazione tra il sovraccarico e l'override di un metodo. Comunque questo articolo favorisce il tuo suggerimento - Potrebbe essere di interesse: roseindia.net/javatutorials/…
NoChance

Risposte:


23

Questo è un problema relativamente minore rispetto a molte altre cattive pratiche di leggibilità a cui potresti essere sensibile, quindi direi che è soprattutto una questione di gusti come si chiamano i tuoi metodi.

Detto questo, se hai intenzione di fare qualcosa al riguardo, seguirei questa pratica:

  • Sovraccarico se ...

    I metodi obbediscono quasi allo stesso contratto ma funzionano semplicemente su input diversi (immagina un operatore telefonico che può cercare il tuo account tramite il tuo numero di identificazione fiscale personale, il tuo numero di conto o il tuo nome e data di nascita). Ciò include la restituzione dello stesso tipo di output .

  • Usa un nome diverso se ...

    I metodi fanno cose sostanzialmente diverse o restituiscono output diversi (come nel tuo caso). È possibile considerare l'utilizzo di un nome diverso se si accede al database e non lo si fa.

    Inoltre, se il tipo restituito è diverso, cambierei anche il verbo per indicare che:

    Car findById(long id);
    
    List findAllByModel(String model);
    

3
FWIW, direi un po 'più forte: "I metodi obbediscono esattamente allo stesso contratto ..." Vale a dire il tipo / conteggio dell'argomento non importa - la semantica della chiamata di funzione è identica a prescindere. Se l'argomento tipo / conteggio è importante, non dovresti sovraccaricare.
mcmcc,

4

Consiglierei di usare un nome diverso, in ogni caso. È possibile che in futuro, vorrai aggiungere un altro metodo, diciamo List<Car> findByMake(String make), al contrario List<Car> findByModel(String model). Così all'improvviso, chiamare tutto findsmette di avere senso. È inoltre meno probabile che i tuoi metodi vengano utilizzati inavvertitamente se i loro nomi forniscono maggiori informazioni su come dovrebbero essere utilizzati.


1
Ad essere onesti, questo non sarebbe tanto un problema se la funzionalità fosse rappresentata in modo più esplicito dagli oggetti: find(Make val)e find(Model val). Quindi, i metodi di praticità come findByMake(String val)sarebbero molto più chiari su ciò che stanno effettivamente facendo. Dopotutto, a Stringnon è né una marca né un modello, quindi il metodo dovrebbe spiegare cosa sta realmente facendo.
Nicole,

4

Se si rinomina un metodo, non verrà più sovraccaricato. Di per sé, il sovraccarico non rende necessariamente il codice meno leggibile, tuttavia può rendere più difficile seguire l'implementazione se la sintassi non è chiara.

Molte lingue usano il metodo di overloading come mezzo per presentare un'interfaccia alla funzionalità in cui i parametri possono essere opzionali e sono implicite impostazioni predefinite per i parametri opzionali. Ciò è particolarmente vero per le lingue che non supportano una sintassi dei parametri predefinita nella dichiarazione del metodo.

Quindi facendo questo:

void MyMethod(int param1, int param2 = 10)
{
    ...
}

ti salva dal fare questo:

void MyMethod(int param1)
{
    MyMethod(param1, Param2Default);
}

void MyMethod(int param1, int param2)
{
    ....
}

Quanto a ciò che è più leggibile, ciò dipende davvero da te. Personalmente preferisco la seconda opzione, in particolare quando l'elenco dei parametri si sta allungando un po ', ma suppongo che non abbia importanza fino a quando sarai coerente in tutta l'API.

La difficoltà con il sovraccarico si presenta quando si desidera che funzioni che fanno sostanzialmente la stessa cosa e dove si desidera che gli elenchi di parametri siano gli stessi, ma i tipi di ritorno siano diversi. La maggior parte delle lingue non sa come distinguere tra due metodi denominati uguali, ma con tipi di ritorno diversi. A questo punto, devi pensare a utilizzare generics, modificare l'interfaccia dei parametri o rinominare uno dei tuoi metodi per indicare la differenza nel tipo restituito. È qui che la leggibilità può diventare un grosso problema, se non ti accontenti di uno schema di denominazione semplice e chiaro per affrontare situazioni come questa.

Denominare i metodi sovraccaricati GetSomething()e GetSomethingEx()non dirò molto su quali sono le differenze tra i metodi, in particolare se sono i tipi di restituzione le uniche differenze tra di loro. D'altra parte, GetSomethingAsInt()e GetSomethingAsString()ti dico qualcosa in più su ciò che stanno facendo i metodi, e sebbene non strettamente un sovraccarico, indica che i due metodi fanno cose simili, ma restituiscono tipi di valore diversi. So che ci sono altri modi in cui potresti nominare i metodi, tuttavia ai fini di illustrare il punto, questi esempi grezzi dovrebbero fare.

Nell'esempio dei PO, la ridenominazione non è strettamente necessaria perché i parametri del metodo sono diversi, tuttavia rende le cose un po 'più chiare nominare un metodo in modo più specifico. Alla fine, si riduce davvero al tipo di interfaccia che desideri presentare ai tuoi utenti. Una decisione sull'opportunità di non sovraccaricare non dovrebbe essere presa esclusivamente sulla base della propria percezione della leggibilità. I metodi di sovraccarico possono ad esempio semplificare un'interfaccia API e ridurre il numero di metodi che uno sviluppatore potrebbe aver bisogno di ricordare, d'altra parte, può offuscare l'interfaccia a un livello che richiede quindi allo sviluppatore di leggere la documentazione del metodo per capire quale forma del metodo da utilizzare, mentre avere un numero di metodi simili ma descrittivamente nominati può rendere più evidente la lettura di un nome di metodo sul suo scopo.


0

Favorire il sovraccarico purché i metodi restituiscano la stessa cosa e seguano lo stesso contratto. Il sovraccarico libera il codice chiamante dall'impegnarsi inutilmente nel tipo di parametro.

Supponiamo che la funzione chiamante riceva una query di ricerca come parametro ed esegua qualche altra elaborazione prima e / o dopo la chiamata a find.

void tryToSellCars(String which) {
    /* grab an airhorn, inflatable tube guy... */
    List<Car> cars = find(which);
    /* expound virtues of each car in detail... */
}

Se si desidera modificare il tipo di query per qualsiasi motivo lungo la strada (ad esempio da una semplice stringa ID a un oggetto query completo di qualche tipo) è possibile apportare tale modifica nella funzione chiamante semplicemente cambiando la firma della funzione per accettare il nuovo tipo di parametro senza preoccuparsi di cambiare il metodo che chiama sulla tua classe.

void tryToSellCar(CarQuery which) {
    /* grab airhorn, inflate tube guy... */
    List<Car> cars = find(which)
    /* expound virtues of each car in detail... */
}

Se implementate findByIde findByQueryObjectseparatamente, dovreste dare la caccia a ogni chiamata per apportare quella modifica. Nell'esempio, ho cambiato solo una parola e ho finito.


Questa risposta presuppone, naturalmente, che si sta utilizzando un linguaggio che supporta il sovraccarico con errori di compilazione per un parametro non valido. Se stai scrivendo JavaScript o Ruby o qualsiasi altra lingua che non supporta in modo nativo il sovraccarico, utilizzerei sempre il verboso findByFooper rilevare in precedenza i tipi non corrispondenti.
sqykly,
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.