it-swarm-eu.dev

Standard vs Impl bei der Implementierung von Schnittstellen in Java

Nach dem Lesen von Sollten Paketnamen Singular oder Plural sein? kam mir der Gedanke, dass ich noch nie eine richtige Debatte über einen meiner Lieblingsprobleme gesehen habe: das Benennen von Implementierungen von Schnittstellen.

Nehmen wir an, Sie haben eine Schnittstelle Order, die auf verschiedene Arten implementiert werden soll, aber es gibt nur die erste Implementierung, wenn das Projekt zum ersten Mal erstellt wird. Entscheiden Sie sich für DefaultOrder oder OrderImpl oder eine andere Variante, um die falsche Zweiteilung zu vermeiden? Und was machen Sie, wenn weitere Implementierungen hinzukommen?

Und am wichtigsten ... warum?

35
Gary Rowe

Namen haben die Möglichkeit, Bedeutung zu vermitteln. Warum würden Sie diese Gelegenheit mit Impl verpassen?

Zuallererst , wenn Sie immer nur eine Implementierung haben werden, beseitigen Sie die Schnittstelle. Es schafft dieses Namensproblem und fügt nichts hinzu. Schlimmer noch, es kann Probleme mit inkonsistenten Methodensignaturen in APIs verursachen, wenn Sie und alle anderen Entwickler nicht darauf achten, immer nur die Schnittstelle zu verwenden.

Vorausgesetzt, wir können davon ausgehen, dass jede Schnittstelle hat oder hat zwei oder mehr Implementierungen.

  • Wenn Sie gerade nur eine haben und nicht wissen, inwiefern sich die andere unterscheidet, ist Standard ein guter Anfang.

  • Wenn Sie gerade zwei haben, benennen Sie jeden nach seinem Zweck.

    Beispiel: Vor kurzem hatten wir einen konkreten Klassenkontext (in Bezug auf eine Datenbank). Es wurde erkannt, dass wir in der Lage sein mussten, einen Kontext darzustellen, der offline war. Daher wurde der Name Context für eine neue Schnittstelle verwendet (um die Kompatibilität für alte APIs zu gewährleisten), und eine neue Implementierung wurde erstellt . OfflineContext . Aber raten Sie mal, in was das Original umbenannt wurde? Das ist richtig, ContextImpl (yikes).

    In diesem Fall wäre DefaultContext wahrscheinlich in Ordnung, und die Leute würden es bekommen, aber es ist nicht so beschreibend, wie es sein könnte. Wenn es nicht offline ist, was ist es dann? Also gingen wir mit: OnlineContext .


Sonderfall: Verwenden des Präfixes "I" für Schnittstellen

Eine der andere Antworten schlug vor, das I-Präfix für Schnittstellen zu verwenden. Vorzugsweise müssen Sie dies nicht brauchen.

Wenn Sie jedoch sowohl eine Schnittstelle für benutzerdefinierte Implementierungen benötigen, als auch eine primäre konkrete Implementierung , die häufig verwendet wird, und der grundlegende Name dafür ist einfach zu einfach Wenn Sie nur auf eine Benutzeroberfläche verzichten, können Sie in Betracht ziehen, der Benutzeroberfläche "I" hinzuzufügen (es ist jedoch völlig in Ordnung, wenn sie für Sie und Ihr Team immer noch nicht richtig ist).

Beispiel: Viele Objekte können ein "EventDispatcher" sein. Für APIs muss dies einer Schnittstelle entsprechen. Sie möchten jedoch auch einen basic Ereignis-Dispatcher für die Delegierung bereitstellen. DefaultEventDispatcher wäre in Ordnung, aber es ist ein bisschen lang, und wenn Sie den Namen oft sehen, bevorzugen Sie könnte Verwenden Sie den Basisnamen EventDispatcher für die konkrete Klasse und implementieren Sie IEventDispatcher für benutzerdefinierte Implementierungen:

/* Option 1, traditional verbose naming: */
interface EventDispatcher { /* interface for all event dispatchers */ }
class DefaultEventDispatcher implements EventDispatcher {
  /* default event dispatcher */
}

/* Option 2, "I" abbreviation because "EventDispatcher" will be a common default: */
interface IEventDispatcher { /* interface for all event dispatchers */ }
class EventDispatcher implements IEventDispatcher {
  /* default event dispatcher. */
}
60
Nicole

Ich entscheide die Benennung nach dem Anwendungsfall der Schnittstelle.

Wenn die Schnittstelle für Entkopplung verwendet wird, wähle ich Impl für Implementierungen.

Wenn der Zweck der Schnittstelle Verhaltensabstraktion ist, werden die Implementierungen nach dem benannt, was sie konkret tun. Ich füge dem oft den Schnittstellennamen hinzu. Wenn die Schnittstelle also Validator heißt, verwende ich FooValidator.

Ich finde, dass Default eine sehr schlechte Wahl ist. Erstens verschmutzt es die Funktionen zur Code-Vervollständigung, da die Namen immer damit beginnen. Die andere Sache ist, dass sich ein Standard im Laufe der Zeit ändern kann. Was also zuerst ein Standard sein könnte, kann einige Zeit später eine veraltete Funktion sein. Entweder benennen Sie Ihre Klassen immer um, sobald sich die Standardeinstellungen ändern, oder Sie leben mit irreführenden Namen.

15
SpaceTrucker

Ich stimme der Antwort von Nicole zu (insbesondere, dass die Schnittstelle in den meisten Fällen wahrscheinlich nicht erforderlich ist), aber zur Diskussion werde ich eine andere Alternative als OrderImpl und DefaultOrder herauswerfen: Verstecken Sie die Implementierung hinter einer statischen Factory-Methode wie Orders.create(). Zum Beispiel:

public final class Orders {
  public static Order create() {
    return new Order() {
      // Implementation goes here.
    };
  }
}

Bei diesem Ansatz kann die Implementierung eine anonyme innere Klasse sein oder eine private Klasse mit Default oder Impl im Namen, oder sie kann ganz anders benannt werden. Unabhängig davon, welche Wahl getroffen wird, muss sich der Anrufer nicht darum kümmern, sodass Sie jetzt und später mehr Flexibilität erhalten, wenn Sie sich entscheiden, diese zu ändern.

Einige gute Beispiele für dieses Muster in der Praxis sind die Java.util.Collections und Java.util.concurrent.Executors Dienstprogrammklassen, deren Methoden versteckte Implementierungen zurückgeben. Wie Effective Java erwähnt (in Punkt 1)), kann dieses Muster dazu beitragen, das "konzeptionelle Gewicht" der API kleiner zu halten.

8
Andrew McNamee

Ich gehe immer für OrderImpl, einfach weil es direkt nach der Order -Schnittstelle alphabetisch angezeigt wird.

3
Ben Hoffstein

Ich denke, dass Standard in einigen Fällen zwar sinnvoll sein kann, es jedoch hilfreicher wäre, die Implementierung zu beschreiben. Wenn Ihre Schnittstelle also UserProfileDAO ist, können Ihre Implementierungen UserProfileSQLDAO oder UserProfileLDAPDAO oder so ähnlich sein.

1
jiggy

wenn möglich, benenne es nach dem, was/wie es seine Sache macht.

normalerweise benennt man es am schlechtesten nach der Art und Weise, wie es verwendet werden soll.

Wenn es als Basisklasse für die Implementierung verwendet werden soll, können Sie BaseX oder AbstractX verwenden (wenn es abstrakt ist (aber versuchen Sie, die Funktionsweise zu verbessern, denn wenn es nichts getan hat, würden Sie es nicht erstellen, haben Sie es bereits) Schnittstelle). Wenn es eine möglichst einfache Funktionalität bietet und erwartet wird, dass es direkt verwendet wird (ohne es zu erweitern), wenn diese Funktionalität ausreicht, können Sie es SimpleX oder BasicX nennen.

Wenn es verwendet wird, sofern keine andere Implementierung bereitgestellt wird, nennen Sie es DefaultX

0
user470365

Versuchen Sie herauszufinden, was an der Klasse konkreter oder spezifischer ist als die Schnittstelle, und integrieren Sie dies in den Namen.

Angenommen, Sie haben eine Schnittstelle für persistente Daten, FooDao. Die Persistenz kann in einer Einfachdatei, einem XML-Dokument, einer Tabelle, einer relationalen Datenbank, einer nicht relationalen Datenbank usw. bestehen. Wenn die Klasse Daten in einer SQL-Datenbank persistiert, versuchen Sie, FooSql implementiert FooDao.

Wenn Sie Code haben, der für einen relationalen Datenbankanbieter spezifisch ist, versuchen Sie es mit FooMssql, FooOracle oder FooDb2. Oder vielleicht passen FooDaoMssql oder FooDaoPostgre besser zu Ihren Zwecken.

Der Punkt ist, fügen Sie nicht nur Buchstaben hinzu, die nur dem Zweck dienen, eine eindeutige Kennung zu erstellen. versuchen Sie, dem Namen etwas aussagekräftigeres zu geben. Das hat zwei gute Effekte. Es teilt dem nächsten Entwickler immer noch mehr Bedeutung mit, selbst wenn Sie nur eine implementierende Klasse haben. Selbst wenn Sie mit nur einer Implementierungsklasse beginnen und jemals eine andere Implementierung benötigen, werden Sie keine Namen wie ..Impl und ..Impl2 oder ..Impl und ..Mongo finden.

0
Chris Golledge

Sie können die Schnittstelle mit dem Präfix I (IWhatever) benennen und dann die Implementierung Whatever durchführen.

Offizielle Java Code-Konventionen erzählen nichts über diese Art der Benennung von Schnittstellen, diese Art der Benennung hilft jedoch bei der Erkennung und Navigation.

0
user1449