Ist es eine sichere Praxis, Standardmethoden als Version von Merkmalen für Arme in Java 8 zu verwenden?
Einige behaupten, es könnte Pandas traurig machen, wenn man sie nur deswegen benutzt, weil es cool ist, aber das ist nicht meine Absicht. Es wird auch oft daran erinnert, dass Standardmethoden eingeführt wurden, um die API-Entwicklung und die Abwärtskompatibilität zu unterstützen, was wahr ist, aber dies macht es nicht falsch oder verdreht, sie als Merkmale an sich zu verwenden.
Ich denke an folgenden praktischen Anwendungsfall :
public interface Loggable {
default Logger logger() {
return LoggerFactory.getLogger(this.getClass());
}
}
Oder definieren Sie vielleicht ein PeriodTrait
:
public interface PeriodeTrait {
Date getStartDate();
Date getEndDate();
default isValid(Date atDate) {
...
}
}
Zugegeben, Komposition könnte verwendet werden (oder sogar Hilfsklassen), aber sie scheint ausführlicher und unübersichtlicher zu sein und erlaubt es nicht, vom Polymorphismus zu profitieren.
Ist es also in Ordnung / sicher, Standardmethoden als Grundmerkmale zu verwenden , oder sollte ich mir Sorgen über unvorhergesehene Nebenwirkungen machen?
Mehrere Fragen zu SO beziehen sich auf Java- und Scala-Merkmale. Darum geht es hier nicht. Ich frage auch nicht nur nach Meinungen. Stattdessen suche ich nach einer maßgeblichen Antwort oder zumindest nach Erkenntnissen vor Ort: Wenn Sie Standardmethoden als Merkmale für Ihr Unternehmensprojekt verwendet haben, hat sich herausgestellt, dass es sich um eine Zeitbombe handelt?
quelle
Antworten:
Die kurze Antwort lautet: Es ist sicher, wenn Sie sie sicher verwenden :)
Die snarky Antwort: Sag mir, was du mit Eigenschaften meinst, und vielleicht gebe ich dir eine bessere Antwort :)
In aller Ernsthaftigkeit ist der Begriff "Merkmal" nicht genau definiert. Viele Java-Entwickler sind mit Merkmalen am besten vertraut, da sie in Scala ausgedrückt werden. Scala ist jedoch weit davon entfernt, die erste Sprache zu sein, die Merkmale aufweist, entweder im Namen oder in der Wirkung.
In Scala sind Merkmale beispielsweise zustandsbehaftet (können
var
Variablen enthalten). In der Festung sind sie reines Verhalten. Javas Schnittstellen zu Standardmethoden sind zustandslos. Bedeutet das, dass sie keine Eigenschaften sind? (Hinweis: Das war eine Trickfrage.)Auch in Scala werden Merkmale durch Linearisierung zusammengesetzt. Wenn die Klasse
A
MerkmaleX
und erweitertY
, bestimmt die Reihenfolge, in derX
undY
gemischt werden, wie Konflikte zwischenX
undY
gelöst werden. In Java ist dieser Linearisierungsmechanismus nicht vorhanden (er wurde teilweise abgelehnt, weil er zu "un-Java-ähnlich" war.)Der Hauptgrund für das Hinzufügen von Standardmethoden zu Schnittstellen war die Unterstützung der Schnittstellenentwicklung , aber wir waren uns bewusst, dass wir darüber hinausgehen. Ob Sie dies als "Interface Evolution ++" oder "Traits--" betrachten, ist eine Frage der persönlichen Interpretation. Um Ihre Frage zur Sicherheit zu beantworten ... Solange Sie sich an das halten, was der Mechanismus tatsächlich unterstützt, anstatt zu versuchen, ihn auf etwas zu dehnen, das er nicht unterstützt, sollte es Ihnen gut gehen.
Ein wichtiges Entwurfsziel war, dass Standardmethoden aus Sicht des Clients einer Schnittstelle nicht von "normalen" Schnittstellenmethoden zu unterscheiden sind. Die Standardeinstellung einer Methode ist daher nur für den Designer und Implementierer der Schnittstelle interessant .
Hier sind einige Anwendungsfälle, die innerhalb der Entwurfsziele liegen:
Schnittstellenentwicklung. Hier fügen wir einer vorhandenen Schnittstelle eine neue Methode hinzu, die eine sinnvolle Standardimplementierung in Bezug auf vorhandene Methoden auf dieser Schnittstelle aufweist. Ein Beispiel wäre das Hinzufügen der
forEach
Methode zuCollection
, wobei die Standardimplementierung in Bezug auf dieiterator()
Methode geschrieben wird."Optionale" Methoden. Hier sagt der Designer einer Schnittstelle: "Implementierer müssen diese Methode nicht implementieren, wenn sie bereit sind, mit den damit verbundenen Einschränkungen der Funktionalität zu leben." Zum Beispiel
Iterator.remove
wurde eine Standardeinstellung gegeben, die wirftUnsupportedOperationException
; Da die überwiegende Mehrheit der ImplementierungenIterator
dieses Verhaltens ohnehin aufweist, ist diese Methode standardmäßig im Wesentlichen optional. (Wenn das Verhalten vonAbstractCollection
als Standardwert für ausgedrückt würdeCollection
, könnten wir dasselbe für die mutativen Methoden tun.)Convenience-Methoden. Dies sind Methoden, die nur der Einfachheit halber dienen und wiederum im Allgemeinen in Form von nicht standardmäßigen Methoden für die Klasse implementiert werden. Die
logger()
Methode in Ihrem ersten Beispiel ist ein vernünftiges Beispiel dafür.Kombinatoren. Hierbei handelt es sich um Kompositionsmethoden, mit denen neue Instanzen der Schnittstelle basierend auf der aktuellen Instanz instanziiert werden. Zum Beispiel sind die Methoden
Predicate.and()
oderComparator.thenComparing()
Beispiele für Kombinatoren.Wenn Sie eine Standardimplementierung bereitstellen, sollten Sie auch eine Spezifikation für die Standardimplementierung angeben (im JDK verwenden wir hierfür das
@implSpec
Javadoc-Tag), damit Implementierer besser verstehen, ob sie die Methode überschreiben möchten oder nicht. Einige Standardeinstellungen, wie Convenience-Methoden und Kombinatoren, werden fast nie überschrieben. andere, wie optionale Methoden, werden häufig überschrieben. Sie müssen genügend Spezifikationen (nicht nur Dokumentation) darüber bereitstellen, was die Standardeinstellung verspricht, damit der Implementierer eine vernünftige Entscheidung darüber treffen kann, ob er sie überschreiben muss.quelle
MouseListener
? Soweit dieser API-Stil sinnvoll ist, passt er in den Bucket "Optionale Methoden". Stellen Sie sicher, dass Sie die Option klar dokumentieren!MouseListener
. Danke für die Antwort.