Abstrakte Methoden
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 44 von 110.
Eine abstrakte Methode ist eine Methode, die innerhalb einer abstrakten Klasse deklariert wird und keinen Rumpf hat. Sie definiert die Methodensignatur, überlässt die Implementierung jedoch jeder Unterklasse. Jede Klasse, die die abstrakte Klasse erweitert, muss alle abstrakten Methoden überschreiben, andernfalls ist sie ebenfalls abstrakt.
abstract class Animal {
// Abstrakte Methode - kein Rumpf, muss von Unterklassen implementiert werden
String makeSound();
// Konkrete Methode - hat einen Rumpf, wird von allen Unterklassen geteilt
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
@override
String makeSound() {
return 'Woof!'; // Muss Implementierung bereitstellen
}
}
class Cat extends Animal {
@override
String makeSound() {
return 'Meow!'; // Unterschiedliche Implementierung, gleiche Signatur
}
}Wenn eine Unterklasse vergisst, eine abstrakte Methode zu implementieren, gibt Dart einen Kompilierfehler aus. Das ist der entscheidende Punkt – abstrakte Methoden erzwingen einen Vertrag. Jede Unterklasse hat diese Methode garantiert, sodass Sie sie sicher auf jeder Instanz des abstrakten Typs aufrufen können.
// Du kannst den abstrakten Typ als Variablentyp verwenden
Animal a = Dog();
print(a.makeSound()); // Wuff!
Animal b = Cat();
print(b.makeSound()); // Miau!Abstrakte Methoden unterscheiden sich von konkreten Methoden in einer abstrakten Klasse. Konkrete Methoden haben einen Rumpf und werden unverändert vererbt. Abstrakte Methoden haben keinen Rumpf und müssen überschrieben werden.
Sie können beides in derselben abstrakten Klasse mischen, um ein bestimmtes Verhalten zu teilen, während Sie Unterklassen zwingen, ihr eigenes Verhalten für andere zu definieren.
| Merkmal | Abstrakte Methode | Konkrete Methode |
|---|---|---|
| Hat einen Rumpf | Nein | Ja |
| Muss überschrieben werden | Ja | Nein |
| Zweck | Vertrag erzwingen | Verhalten teilen |
| Wo | Nur in abstrakten Klassen | In jeder Klasse |
Aufgabe
EinfachLassen Sie uns einen Formenkalkulator erstellen, der abstrakte Methoden in Aktion demonstriert. Sie werden eine abstrakte Klasse mit abstrakten Methoden definieren, die jede Form unterschiedlich implementieren muss, und diese Formen dann über eine gemeinsame Schnittstelle verwenden.
Sie werden Ihren Code in vier Dateien organisieren:
shape.dart: Definieren Sie eine abstrakte KlasseShapemit einemfinalFeldcolor(String) und einem Konstruktor, der dieses initialisiert. Deklarieren Sie zwei abstrakte Methoden:double area()unddouble perimeter(). Fügen Sie außerdem eine konkrete Methodedescribe()hinzu, dieA [color] shape with area: [area] and perimeter: [perimeter]ausgibt. Daarea()undperimeter()abstrakt sind, wird jede Unterklasse ihre eigene Berechnung bereitstellen, aberdescribe()funktioniert für alle, ohne überschrieben zu werden.circle.dart: Erstellen Sie eine KlasseCircle, dieShapeerweitert. Sie hat einfinalFeldradius(double). Ihr Konstruktor nimmtcolorundradiusentgegen und übergibtcoloransuper. Implementieren Siearea()so, dass sie3.14 * radius * radiuszurückgibt, undperimeter()so, dass sie2 * 3.14 * radiuszurückgibt.rectangle.dart: Erstellen Sie eine KlasseRectangle, dieShapeerweitert. Sie hatfinalFelderwidthundheight(beide double). Ihr Konstruktor nimmtcolor,widthundheightentgegen und übergibtcoloransuper. Implementieren Siearea()so, dass siewidth * heightzurückgibt, undperimeter()so, dass sie2 * (width + height)zurückgibt.main.dart: Importieren Sie alle Dateien. Erstellen Sie einenCirclemit der Farbe'red'und dem Radius5.0sowie einRectanglemit der Farbe'blue', der Breite4.0und der Höhe6.0. Rufen Siedescribe()für jede Form auf. Erstellen Sie dann eineList<Shape>, die beide Formen enthält, durchlaufen Sie die Liste in einer Schleife und geben SieArea: [area]für jede Form aus.
Erwartete Ausgabe:
A red shape with area: 78.5 and perimeter: 31.400000000000002
A blue shape with area: 24.0 and perimeter: 20.0
Area: 78.5
Area: 24.0Spickzettel
Eine abstrakte Methode ist eine Methode, die in einer abstrakten Klasse ohne Rumpf deklariert wird. Unterklassen müssen sie überschreiben, um ihre eigene Implementierung bereitzustellen.
abstract class Animal {
// Abstrakte Methode - kein Rumpf
String makeSound();
// Konkrete Methode - hat einen Rumpf
void breathe() {
print('Breathing...');
}
}Unterklassen müssen alle abstrakten Methoden implementieren:
class Dog extends Animal {
@override
String makeSound() {
return 'Woof!';
}
}
class Cat extends Animal {
@override
String makeSound() {
return 'Meow!';
}
}Sie können den abstrakten Typ als Variablentyp verwenden:
Animal a = Dog();
print(a.makeSound()); // Woof!
Animal b = Cat();
print(b.makeSound()); // Meow!| Merkmal | Abstrakte Methode | Konkrete Methode |
|---|---|---|
| Hat Rumpf | Nein | Ja |
| Muss überschrieben werden | Ja | Nein |
| Zweck | Vertrag erzwingen | Verhalten teilen |
| Wo | Nur abstrakte Klasse | Jede Klasse |
Probier es selbst
import 'shape.dart';
import 'circle.dart';
import 'rectangle.dart';
void main() {
// TODO: Erstelle einen Circle mit der Farbe 'red' und dem Radius 5.0
// TODO: Erstelle ein Rectangle mit der Farbe 'blue', der Breite 4.0 und der Höhe 6.0
// TODO: Rufe describe() für den circle auf
// TODO: Rufe describe() für das rectangle auf
// TODO: Erstelle eine List<Shape>, die beide Formen enthält
// TODO: Iteriere durch die Liste und gib "Area: [area]" für jede Form aus
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor