Das hat mich verblüfft, warum es besser ist, eine abstrakte Klasse zu haben. Also muss ich sagen, dass ich Bereiche mit verschiedenen Formen (Kreis, Rechteck) berechnen muss. Mir wurde beigebracht, es sei besser, eine abstrakte / Interface-Form zu haben und dann Klassen wie Rectangle, Circle, das es erweitert.
Ich habe den folgenden Code erstellt
%Vor%Es scheint, dass die Formklasse keinen Zweck erfüllt. Ich kann eine getArea-Implementation in der Shape-Klasse nicht durchführen, da verschiedene Formen die Fläche unterschiedlich berechnen. Ich könnte nur die Formklasse entfernen und meinen Code vereinfachen.
Was wäre der eigentliche Zweck einer abstrakten / Interface-Klassenform? Vielen Dank im Voraus für jede Erklärung
Es scheint, dass die Formklasse keinen Zweck erfüllt. Ich kann eine getArea-Implementation in der Shape-Klasse nicht durchführen, da verschiedene Formen die Fläche unterschiedlich berechnen. Ich könnte nur die Formklasse entfernen und meinen Code vereinfachen.
Angenommen, Sie haben ein Bild, das aus mehreren Formen besteht - einigen Kreisen, einigen Rechtecken usw. Sie können alle diese Formen in List<Shape>
speichern und dann die Gesamtfläche berechnen mit:
Wie würden Sie das tun, wenn Sie keine gemeinsame Shape
-Klasse oder Schnittstelle hätten? Ihre Klasse Picture
müsste über jede einzelne Formklasse Bescheid wissen, anstatt die Gemeinsamkeit zwischen den verschiedenen Formklassen zu verwenden, um den Code allgemeiner zu gestalten.
Betrachten Sie als weiteres Beispiel Streams. Stellen Sie sich vor, wir hätten nicht die Klasse InputStream
- wir hatten nur die einzelnen Unterklassen. Dann müssten Sie jedes Mal, wenn Sie Code schreiben, der einige Daten lesen muss, eine Überladung für jede einzelne Unterklasse bereitstellen, die Sie handhaben möchten, obwohl der Code in jeder Methode genau gleich wäre. InputStream
abstrahiert die Unterschiede und stellt die allgemeine Funktionalität (Lesen, Überspringen usw.) zur Verfügung. Auf diese Weise können Sie eine einzelne Methode schreiben, die nur InputStream
benötigt, und dann mit einer FileInputStream
oder einer ByteArrayInputStream
etc ... aufrufen, ohne dass die Methode sich darum kümmern muss, welche sie empfängt.
Wenn Sie eine beliebige Shape
an eine Methode übergeben möchten, können Sie Folgendes tun:
Dies nennt man Polymorphismus. Wenn es keine abstrakte Klasse oder Schnittstelle gibt, können Sie dies nicht tun.
Sie können eine Schnittstelle oder eine abstrakte Klasse verwenden, wenn Sie Klassen basierend auf bestimmten Verhaltensweisen oder Eigenschaften gruppieren möchten. Dadurch können Sie die Schnittstelle / abstrakte Klasse als Parametertypen oder in Generika verwenden. In Ihrem Fall können Sie beispielsweise Folgendes tun:
List <Shape>
. getArea()
auf Ihrer Shape-Klasse / Schnittstelle. Sie können es dann in einer Methode whichIsGreater (Shape shape1, Shape shape2)
verwenden, die getArea()
method in ihrer Implementierung verwendet. Es gibt noch einen weiteren sehr wichtigen Aspekt der Verwendung von Interfaces oder abstrakten Klassen. Wenn Sie für Ihre Klassen eine abstrakte Klasse (oder eine Schnittstelle) definiert haben, wird die Absicht Ihres Codeentwurfs angezeigt. Jemand, der deinen Code aufheben würde, hätte viel leichter die Aufgabe, ihn mit einer korrekt definierten Vererbung zu verstehen.
Das Ziel eines guten Code-Designs ist nicht wirklich den kürzestmöglichen Code zu schreiben. Es geht um effizienten, aber auch klaren und selbst dokumentierten Code.
Zur Vollständigkeit meiner Antwort habe ich einige der in anderen Antworten angesprochenen Punkte wiederholt - keine Missachtung beabsichtigt.
In Ihrem speziellen Fall sollte Shape ein interface
nicht ein abstract class
sein.
Ein interface
ist im Grunde ein abstract class
mit nur public
Methoden und keine Implementierungen. Ein abstract class
macht Sinn, wenn Sie in der Lage sind, eine bestimmte Methode zu implementieren, die für alle oder zumindest die meisten implementierenden Subklassen korrekt ist. Es ist eine Anwendung des DRY-Prinzips in diesem Fall.
Warum sollten Sie sich mit abstrakten Klassen oder Interfaces beschäftigen?
Weil du jetzt nur ein List<Shape>
haben kannst, wo du alle Arten von verschiedenen Formen einfügen kannst und du brauchst dich nicht darum zu kümmern, welche Form es genau ist. Die JVM erledigt die Arbeit für Sie und wählt aus, welche getArea
Implementierung sie wählen soll.
Tags und Links java inheritance polymorphism
Nach dieser jsbin habe ich eine %code% -Liste und eine Schaltfläche. Wenn Sie auf den Button klicken, fügen Sie zu %code% hinzu und ich möchte wissen, welches Ereignis von %code% ausgelöst wurde (update, receive) und wenn Sie das Ereignis gefunden haben, machen Sie etwas für dieses Ereignis.
Wenn der Benutzer zum Beispiel auf %code% button klickt, möchte ich wissen, welches Ereignis ausgelöst wird und etwas für das Ereignis tun. zum Beispiel, wenn Update Feuer mache ich etwas in Update-Methode von sortierbaren
%Vor%Da der Aktualisierungsrückruf als Option des sortierbaren Widgets definiert ist, kann er als solcher durch Aufruf der optionsmethode :
%Vor%Der Updaterückruf erwartet zwei Parameter , die %code% und eine %code% . Der %code% kann auf null gesetzt werden und der %code% muss mit allen Eigenschaften definiert werden, die Ihr %code% erwartet:
%Vor%Das Problem
Wenn Sie den %code% -Rückruf als Teil der Widget-Optionen %code% definieren, wird ein Ereignis namens %code% an das Widget gebunden. Mit anderen Worten, die Callback-Funktion, die durch die %code% -Option definiert ist, wird zwar aufgerufen, aber ein Ereignis mit diesem Namen wird in dieser Situation nicht ausgelöst.
Die Lösung
Wenn Sie das Ereignis manuell auslösen möchten, müssen Sie es auch manuell binden . Beachten Sie, dass das Ereignis auch automatisch vom normalen Verhalten des Widgets ausgelöst wird (z. B. wenn ein Benutzer die Elemente im Widget sortiert).
Zum Beispiel:
HTML
%Vor%JS
%Vor%