Ich wechselte von Java 1.4 (früheres Unternehmen) zu Java 1.6 (neues Unternehmen). Ich habe beobachtet, dass im Fall von 1.4 die meisten proprietären Frameworks unter Verwendung von Interfaces und Template-Mustern definiert wurden, während bei 1.6 die meisten Frameworks um Generics definiert sind.
Während ich immer noch versuche, Generics in den Griff zu bekommen, ist meine Frage: Ist das ein richtiger Designansatz? Schnittstellen machen Ihr Design flexibler / entkoppelter. Während Generics, implementieren Typ Sicherheit und erzwingen Sie, um eine bestimmte Art von Klasse zu übergeben. Es hilft nicht wirklich beim Entkoppeln deines Codes. Ist das richtig?
Ein Beispiel -
%Vor%stattdessen wäre das Design flexibler, wenn es so wäre.
%Vor% Ich würde nicht sagen, dass irgendetwas Generika gegen Schnittstellen waren, jede hat ihre unterschiedlichen Bedürfnisse und Verwendungen. Die Verwendung generischer Parameter in der im ursprünglichen Post erwähnten Weise dient mehreren Zwecken. Es ermöglicht Entwicklern, die Basisklassen zu definieren, aus denen die Feldobjekttypen der Klasse bestehen. Dadurch kann der Entwickler Klassenobjekte als Parameter akzeptieren, mit denen er die tatsächlichen Objekte erstellen und die Felder setzen oder einfach das gesamte Objekt übernehmen kann. Das Problem, das sich auf das Verwenden von Klassenobjekten bezieht, anstatt new T()
oder so auszuführen, ist bekannt als type-Löschung .
Ein weiterer Vorteil der Verwendung von Generika ist, dass Sie nicht immer die ganze Zeit tippen müssen, wenn Sie Felder oder Methoden aus einer Superklasse verwenden - Sie kennen ihre Typen persönlich, aber Java hat diese Art von Informationen nirgends gespeichert. Ein weiterer Vorteil ist, dass all Ihre Getter / Setter-Methoden die generischen Parameter verwenden können und eine vernünftigere Front gegenüber anderen Objekten verfügbar machen, die darauf angewiesen sind, dass Sie spezialisierte Felder in dem oben genannten Objekt einrichten.
Das Problem bei der Verwendung von Interfaces für Generics besteht darin, dass Sie zusätzliche Methoden benötigen, um auf die spezialisierten Typen zuzugreifen und sie zu konvertieren, bevor Sie sie zurückgeben (oder eingehende Typen prüfen und dann Felder auf die Objekte setzen). Es macht das Design komplexer und hilft nicht wirklich bei der Entkopplung.
Wie ich in einem Kommentar erwähnt habe, werden alle Unterklassen diese Typparameter setzen und dem Benutzer nichts offenlegen. Sie können also etwas wie class MegaSignupWizard extends SignupWizard<MegaSignupSection, MegaSignupObject, MegaSignupListener, MegaSignupView>
haben, und alles bleibt perfekt gültig, wobei MegaSignupWizard
Zugriff auf spezialisierte Methoden in den Klassen hat, ohne dass eine Umwandlung erforderlich ist. Nun, das ist cool:)
Generics können Sie Methoden für den allgemeinen Typ implementieren, während Schnittstellen nur die Signaturen definieren. Vielleicht wird es manchmal missbraucht, um wie Scalas trait
zu handeln, aber meistens dienen sie zwei verschiedenen Zwecken. Wenn alles eine Schnittstelle ist, wird es eine Menge doppelten Code oder Delegationen zu einer Hilfsklasse geben.
Ich habe bemerkt, dass viele der neuen Frameworks dazu neigen, Annotationen anstelle von Interfaces zu verwenden, aber ich habe nicht bemerkt, dass sie Generics anstelle von Interfaces verwenden (was auch immer es bedeutet - bitte erklären Sie mehr).
Mit Hilfe von Generika ist es möglich, einige Code-Duplizierungen zu reduzieren und die Typsicherheit zu verbessern, wenn Sie eine Schnittstelle mit generischen Typparametern haben und dieselbe Schnittstelle für viele verschiedene Typen arbeiten kann. Die Sammlungen im Paket java.util sind ein gutes Beispiel wenn Generika nützlich sind.
Im Fall von Annotationen empfinde ich manchmal, dass sie überstrapaziert sind und eine Schnittstelle besser wäre - zum Beispiel mit einer Schnittstelle ist es einfach zu wissen, welche Parameter eine Methode verwenden sollte - aber in anderen Fällen ist eine Annotation flexibler und leistungsfähiger.
Ich denke, es sind Generika und Schnittstellen, da jede Schnittstelle selbst Generika nutzen kann. Das Problem, das ich sehe, wenn Sie beginnen, generische (abstrakte) Klassen zu verwenden, verlieren Sie die Flexibilität der Verwendung der Zusammensetzung. Während es nichts Schlechtes an der Vererbung als solcher gibt, muss man es entwerfen und es gibt viele Fallstricke.
Sieh dir Jung2 an, um zu sehen, wo Generika wirklich mächtig werden. Grundsätzlich kann jedes Objekt ein Eckpunkt oder eine Kante sein, die für einige wirklich interessante Ideen in Netzwerkalgorithmen sorgt. Sie können dies nicht nur mit Schnittstellen tun.
Ich bin mir nicht sicher, ob deine obige Verwendung auch gut aussieht. Wenn Sie von einem Objekt ausgehen oder eine Schnittstelle implementieren, möchten Sie solche Objekte nicht wirklich weitergeben. Generics werden verwendet, um eine Klasse mit einem abstrakten Typ wie eine Sammlung zu implementieren, die auf alles einwirken kann. Was passiert, wenn ich SignupWizard<int, int, int, int>
überlasse, was absolut gültig ist?
Für diese spezielle Idee möchten Sie vielleicht Schnittstellen verwenden. Eine Schnittstelle, die eine Wizard-Aktion definiert, wobei jedes Objekt sie implementiert und mein Wizard in der Lage ist, .addaction (int position, wizardaction action) zu implementieren. In der Tat ist das definitiv ein Schnittstellenproblem.
Ich stimme den anderen zu - Generika wurden verwendet, wenn sie von Bibliotheken benötigt werden.