Sollten wir überladene Methoden umbenennen?

14

Angenommen, eine Schnittstelle enthält die folgenden Methoden:

Car find(long id);

List<Car> find(String model);

Ist es besser, sie so umzubenennen?

Car findById(long id);

List findByModel(String model);

In der Tat muss jeder Entwickler, der diese API verwendet, nicht in der Benutzeroberfläche nach möglichen Argumenten für anfängliche find()Methoden suchen .

Meine Frage ist also allgemeiner: Welchen Vorteil hat die Verwendung überladener Methoden im Code, da sie die Lesbarkeit beeinträchtigen?

Mik378
quelle
4
Jede Methode ist akzeptabel, solange Sie konsistent sind.
ChrisF
Es gibt eine Beziehung zwischen Überladen und Überschreiben einer Methode. Dieser Artikel ist jedoch für Ihren Vorschlag von Interesse: roseindia.net/javatutorials/…
NoChance

Antworten:

23

Dies ist ein relativ kleines Problem im Vergleich zu vielen anderen schlechten Lesbarkeitspraktiken, für die Sie anfällig sein könnten. Ich würde daher sagen, es ist hauptsächlich eine Frage des Geschmacks, wie Sie Ihre Methoden benennen.

Vor diesem Hintergrund würde ich, wenn Sie etwas dagegen unternehmen wollen, wie folgt vorgehen:

  • Überlastung wenn ...

    Die Methoden entsprechen nahezu demselben Vertrag, funktionieren jedoch nur mit unterschiedlichen Eingaben (stellen Sie sich einen Telefonanbieter vor, der Ihr Konto anhand Ihrer persönlichen Steuer-ID-Nummer, Ihrer Kontonummer oder Ihres Namens und Ihres Geburtstages nachschlagen kann). Dies schließt die Rückgabe des gleichen Ausgabetyps ein .

  • Verwenden Sie einen anderen Namen, wenn ...

    Die Methoden führen erheblich unterschiedliche Aktionen aus oder geben unterschiedliche Ausgaben zurück (wie in Ihrem Fall). Sie können einen anderen Namen verwenden, wenn einer auf die Datenbank zugreift und einer nicht.

    Wenn der zurückgegebene Typ anders ist, würde ich außerdem das Verb so ändern, dass Folgendes angezeigt wird:

    Car findById(long id);
    
    List findAllByModel(String model);
    
Nicole
quelle
3
FWIW, ich würde das etwas deutlicher ausdrücken: "Die Methoden gehorchen genau demselben Vertrag ..." Dh das Argument type / count spielt keine Rolle - die Semantik des Funktionsaufrufs ist unabhängig davon identisch. Wenn das Argument type / count eine Rolle spielt, sollten Sie nicht überladen.
mcmcc
4

Ich würde auf jeden Fall empfehlen, einen anderen Namen zu verwenden. Es ist möglich, dass Sie zu einem späteren Zeitpunkt eine andere Methode hinzufügen möchten List<Car> findByMake(String make), beispielsweise im Gegensatz zu List<Car> findByModel(String model). So plötzlich findmacht es keinen Sinn mehr , alles anzurufen. Es ist auch weniger wahrscheinlich, dass Ihre Methoden versehentlich falsch verwendet werden, wenn ihre Namen weitere Informationen darüber enthalten, wie sie verwendet werden sollen.

Laut Dawood soll Monica wieder eingesetzt werden
quelle
1
Um fair zu sein, wäre dies kein Problem, wenn die Funktionalität expliziter durch Objekte dargestellt würde: find(Make val)und find(Model val). Dann findByMake(String val)wären Convenience-Methoden wie viel klarer, was sie tatsächlich tun. Schließlich ist a Stringweder ein Fabrikat noch ein Modell, daher sollte die Methode erklären, was sie wirklich tut.
Nicole
4

Wenn Sie eine Methode umbenennen, wird sie nicht mehr überladen. An und für sich macht das Überladen den Code nicht unbedingt weniger lesbar, es kann jedoch schwieriger sein, der Implementierung zu folgen, wenn die Syntax nicht klar ist.

Viele Sprachen verwenden Methodenüberladung als Mittel, um eine Schnittstelle für Funktionen bereitzustellen, bei denen die Parameter optional sein können und Standardeinstellungen für die optionalen Parameter impliziert sind. Dies gilt insbesondere für Sprachen, die keine Standardparametersyntax in der Methodendeklaration unterstützen.

Also mach das:

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

erspart Ihnen dies:

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

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

Was lesbarer ist, hängt wirklich von Ihnen ab. Persönlich bevorzuge ich die zweite Option, insbesondere wenn die Parameterliste etwas lang wird, aber ich nehme an, dass es nicht wirklich wichtig ist, solange Sie in Ihrer API konsistent sind.

Die Schwierigkeit beim Überladen entsteht, wenn Sie Funktionen wünschen, die im Wesentlichen dasselbe tun, und wenn Sie möchten, dass die Parameterlisten gleich sind, die Rückgabetypen jedoch unterschiedlich sind. Die meisten Sprachen können nicht zwischen zwei gleichnamigen Methoden mit unterschiedlichen Rückgabetypen unterscheiden. An diesem Punkt müssen Sie überlegen, ob Sie entweder Generika verwenden, die Parameterschnittstelle ändern oder eine Ihrer Methoden umbenennen möchten, um den Unterschied im Rückgabetyp anzuzeigen. Hier kann die Lesbarkeit zu einem großen Problem werden, wenn Sie sich nicht für ein einfaches und klares Benennungsschema entscheiden, um mit solchen Situationen fertig zu werden.

Nennen Sie Ihre überladenen Methoden GetSomething()und GetSomethingEx()sagen Sie nicht viel darüber aus, was die Unterschiede zwischen Ihren Methoden sind, besonders wenn es die Rückgabetypen sind, die die einzigen Unterschiede zwischen ihnen sind. Auf der anderen Seite,GetSomethingAsInt() und GetSomethingAsString()erzählen Sie ein wenig mehr über das, was die Methoden tun, und zwar nicht unbedingt eine Überlastung zu tun zeigen , dass die beiden Methoden tun ähnliche Dinge, aber unterschiedliche Werttypen zurück. Ich weiß, dass es andere Möglichkeiten gibt, Methoden zu nennen, aber zum Zwecke der Veranschaulichung sollten diese groben Beispiele dies tun.

Im OPs-Beispiel ist das Umbenennen nicht unbedingt erforderlich, da die Methodenparameter unterschiedlich sind. Es macht jedoch die Benennung einer Methode etwas klarer. Am Ende kommt es wirklich auf die Art der Benutzeroberfläche an, die Sie Ihren Benutzern präsentieren möchten. Eine Entscheidung darüber, ob Sie nicht überladen möchten, sollte nicht ausschließlich auf Ihrer eigenen Wahrnehmung der Lesbarkeit beruhen. Das Überladen von Methoden kann beispielsweise eine API-Schnittstelle vereinfachen und die Anzahl der Methoden verringern, an die sich ein Entwickler erinnern muss. Andererseits kann es die Schnittstelle in einem Maße verschleiern, dass ein Entwickler die Methodendokumentation lesen muss, um zu verstehen, welches Formular verwendet wird der zu verwendenden Methode, wohingegen eine Reihe von Methoden mit ähnlichem und dennoch beschreibendem Namen es offensichtlicher machen kann, nur einen Methodennamen hinsichtlich seines Zwecks zu lesen.

S.Robins
quelle
0

Bevorzugen Sie das Überladen, solange die Methoden dasselbe zurückgeben und denselben Vertrag befolgen. Durch das Überladen wird der aufrufende Code nicht unnötig an den Parametertyp gebunden.

Angenommen, die aufrufende Funktion empfängt eine Suchabfrage als Parameter und führt vor und / oder nach dem Aufruf von eine andere Verarbeitung durch find.

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

Wenn Sie den Typ dieser Abfrage aus irgendeinem Grund später ändern möchten (z. B. von einer einfachen ID-Zeichenfolge zu einem Abfrageobjekt mit vollem Funktionsumfang), können Sie diese Änderung in der aufrufenden Funktion vornehmen, indem Sie einfach die Funktionssignatur ändern Akzeptieren Sie den neuen Parametertyp, ohne sich Gedanken über die Änderung der Methode zu machen, die er für Ihre Klasse aufruft.

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

Wenn Sie implementieren findByIdund findByQueryObjectseparat, müssten Sie jeden Anruf nachholen, um diese Änderung vorzunehmen. Im Beispiel habe ich nur ein Wort geändert und war fertig.

sqykly
quelle
Diese Antwort setzt natürlich voraus, dass Sie eine Sprache verwenden, die das Überladen mit Kompilierungsfehlern für einen ungültigen Parameter unterstützt. Wenn Sie JavaScript oder Ruby oder eine andere Sprache schreiben, die das Überladen nicht von Haus aus unterstützt, würde ich immer die ausführliche Beschreibung verwenden findByFoo, um Typenkonflikte früher zu erkennen.
sqykly