Dovremmo rinominare i metodi sovraccaricati?

12

Assumi 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 avrà bisogno di consultare l'interfaccia per conoscere i possibili argomenti dei metodi iniziali find() .

Quindi la mia domanda è più generale: Qual è il vantaggio dell'utilizzo di metodi sovraccaricati nel codice poiché riduce la leggibilità?

    
posta Mik378 29.01.2012 - 16:08
fonte

4 risposte

21

Si tratta di un problema relativamente minore rispetto a molte altre pratiche di leggibilità errate a cui potresti essere soggetto, quindi direi che è principalmente una questione di gusti su come nominare i tuoi metodi.

Detto questo, se hai intenzione di fare qualcosa al riguardo, seguirò 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 codice fiscale personale, il numero del tuo account, o il tuo nome e la data di nascita). Ciò include restituire lo stesso tipo di output .

  • Utilizza un nome diverso se ...

    I metodi fanno cose sostanzialmente diverse o restituiscono output diversi (come nel tuo caso). Potresti prendere in considerazione l'utilizzo di un nome diverso se si accede al database e uno no.

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

    Car findById(long id);
    
    List findAllByModel(String model);
    
risposta data 29.01.2012 - 16:20
fonte
4

Consiglierei di usare un nome diverso, in ogni caso. È possibile che in futuro, in futuro, dovrai aggiungere un altro metodo, ad esempio List<Car> findByMake(String make) , a differenza di List<Car> findByModel(String model) . All'improvviso, chiamare tutto find non ha senso. Inoltre, è meno probabile che i tuoi metodi vengano inavvertitamente utilizzati in modo non corretto, se i loro nomi forniscono ulteriori informazioni su come dovrebbero essere utilizzati.

    
risposta data 30.01.2012 - 00:20
fonte
4

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

Molte lingue utilizzano l'overloading dei metodi come mezzo per presentare un'interfaccia alla funzionalità in cui i parametri possono essere facoltativi e i valori predefiniti per i parametri facoltativi sono impliciti. Ciò è particolarmente vero per le lingue che non supportano una sintassi dei parametri predefinita nella dichiarazione del metodo.

Così facendo:

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

ti salva da questo:

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

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

Per quanto è più leggibile, questo dipende davvero da te. Personalmente preferisco la seconda opzione, in particolare quando la lista dei parametri sta diventando un po 'lunga, ma suppongo che non sia importante purché tu sia coerente in tutta la tua API.

La difficoltà con l'overloading si verifica quando si desidera che le funzioni eseguano essenzialmente la stessa cosa e in cui si desidera che gli elenchi dei parametri siano uguali, ma i tipi di restituzione siano diversi. La maggior parte delle lingue non sa come distinguere tra due metodi chiamati lo stesso, ma con diversi tipi di ritorno. A questo punto, è necessario considerare l'utilizzo di generici, la modifica dell'interfaccia dei parametri o la ridenominazione di uno dei 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 tuoi metodi sovraccaricati GetSomething() e GetSomethingEx() non dirà molto su quali siano le differenze tra i tuoi metodi, in particolare se sono i tipi di ritorno le uniche differenze tra loro. D'altra parte, GetSomethingAsInt() e GetSomethingAsString() ti dicono un po 'di più su cosa stanno facendo i metodi, e anche se non strettamente un overload, indichiamo che i due metodi fanno cose simili, ma restituiscono diversi tipi di valore. So che ci sono altri modi in cui puoi dare un nome ai metodi, tuttavia per gli scopi di illustrare il punto, questi esempi grezzi dovrebbero fare.

Nell'esempio OP, la ridenominazione non è strettamente necessaria perché i parametri del metodo sono diversi, tuttavia rende le cose un po 'più chiare per denominare un metodo in modo più specifico. Alla fine, si tratta davvero del tipo di interfaccia che desideri presentare ai tuoi utenti. Una decisione sul fatto di non sovraccaricare non dovrebbe essere presa esclusivamente sulla base della propria percezione della leggibilità. I metodi di overloading possono ad esempio semplificare un'interfaccia API e ridurre il numero di metodi che uno sviluppatore potrebbe dover ricordare, d'altra parte può confondere l'interfaccia con un grado che richiede allo sviluppatore di leggere la documentazione del metodo per capire quale modulo del metodo da usare, mentre avere un certo numero di metodi con nomi simili ma descrittivi può rendere più evidente la lettura del nome di un metodo rispetto al suo scopo.

    
risposta data 30.01.2012 - 04:51
fonte
0

Supporta il sovraccarico fintanto che i metodi restituiscono la stessa cosa e seguono lo stesso contratto. Il sovraccarico libera il codice chiamante dal commettere inutilmente il 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 tale 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 alla funzione di chiamata semplicemente cambiando la firma della funzione per accettare il nuovo tipo di parametro senza preoccuparsi di cambiare il metodo che chiama sulla classe.

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

Se implementi findById e findByQueryObject separatamente, dovrai cercare ogni chiamata per apportare tale modifica. Nell'esempio, ho cambiato solo una parola e ho finito.

    
risposta data 29.10.2013 - 16:34
fonte

Leggi altre domande sui tag