Implementieren vs. Erweitern
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 47 von 110.
Nachdem Sie nun sowohl extends als auch implements verstehen, lassen Sie uns klären, wann welches verwendet werden sollte.
Verwenden Sie extends, wenn Sie Verhalten vererben möchten. Ihre Unterklasse erhält den gesamten Code der Elternklasse kostenlos und kann darauf aufbauen:
class Animal {
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
void bark() {
print('Woof!');
}
}
void main() {
var dog = Dog();
dog.breathe(); // Vererbt - funktioniert automatisch
dog.bark();
}Verwenden Sie implements, wenn Sie eine Struktur garantieren möchten, ohne Code zu erben. Sie müssen jede Methode selbst schreiben:
class Robot implements Animal {
@override
void breathe() {
print('Ventilating circuits...'); // Vollständig benutzerdefinierte Implementierung
}
}Der entscheidende Unterschied: extends besagt „Ich bin ein Typ hiervon“, während implements besagt „Ich kann das, was dies tut“. Ein Dog ist ein Animal und atmet auf dieselbe Weise. Ein Robot ist kein Tier, aber er kann denselben Vertrag mit seiner eigenen Logik erfüllen.
Denken Sie daran: Sie können nur eine Klasse erweitern, aber Sie können viele Schnittstellen implementieren. Wählen Sie extends für echte Vererbungsbeziehungen und implements, wenn Sie Flexibilität benötigen oder einen Vertrag erzwingen möchten, ohne Implementierungsdetails zu teilen.
Aufgabe
EinfachLassen Sie uns ein Arbeitersystem aufbauen, das demonstriert, wann extends im Gegensatz zu implements verwendet werden sollte. Sie werden eine Basisklasse für Arbeiter erstellen und dann beide Ansätze zeigen: eine Klasse, die wirklich ein Arbeiter "ist" und Verhalten erbt, und eine andere, die einfach das "kann", was ein Arbeiter tut, aber mit völlig eigener Logik.
Sie werden Ihren Code in zwei Dateien organisieren:
worker.dart: Definieren Sie hier Ihre Arbeiter-Hierarchie:- Eine
Worker-Klasse mit einerString name-Eigenschaft und einem Konstruktor. Fügen Sie eine Methodework()hinzu, die[name] is working...ausgibt, und eine MethodetakeBreak(), die[name] takes a coffee breakausgibt. - Eine
OfficeWorker-Klasse, dieWorkererweitert (extends). Fügen Sie eineString department-Eigenschaft hinzu. Überschreiben Siework(), um[name] is typing reports in [department]auszugeben, aber behalten Sie das geerbtetakeBreak()-Verhalten bei. - Eine
RobotWorker-Klasse, dieWorkerimplementiert (implements). Fügen Sie eineString model-Eigenschaft hinzu. Da Roboter nicht wirklich Arbeiter sind, aber das tun können, was Arbeiter tun, stellen Sie völlig eigene Implementierungen bereit:work()sollteRobot [model] is assembling partsausgeben undtakeBreak()sollteRobot [model] is rechargingausgeben.
- Eine
main.dart: Importieren Sie Ihre Arbeiter-Datei und demonstrieren Sie beide Ansätze:- Erstellen Sie einen
OfficeWorkernamens'Alice'in der Abteilung'Marketing' - Erstellen Sie einen
RobotWorkermit dem Modell'RX-7' - Rufen Sie für den Büroangestellten
work()und danntakeBreak()auf - Geben Sie eine Leerzeile aus
- Rufen Sie für den Roboter-Arbeiter
work()und danntakeBreak()auf
- Erstellen Sie einen
Beachten Sie, wie OfficeWorker die Methode takeBreak() automatisch erbt, weil sie Worker erweitert - sie "ist" wirklich ein Arbeiter. In der Zwischenzeit muss RobotWorker für alles eine eigene Implementierung bereitstellen, da sie nur das Interface implementiert - sie "kann" das, was ein Arbeiter tut, aber auf ihre eigene roboterhafte Weise.
Erwartete Ausgabe:
Alice is typing reports in Marketing
Alice takes a coffee break
Robot RX-7 is assembling parts
Robot RX-7 is rechargingSpickzettel
Verwenden Sie extends, um Verhalten von einer Elternklasse zu erben. Die Unterklasse erhält automatisch alle Methoden der Elternklasse und kann diese überschreiben:
class Animal {
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
void bark() {
print('Woof!');
}
}
void main() {
var dog = Dog();
dog.breathe(); // Inherited automatically
dog.bark();
}Verwenden Sie implements, um eine Struktur zu garantieren, ohne Code zu erben. Sie müssen für jede Methode eine eigene Implementierung bereitstellen:
class Robot implements Animal {
@override
void breathe() {
print('Ventilating circuits...');
}
}Wichtige Unterschiede:
extends: „Ich bin ein Typ hiervon“ – echte Vererbung mit gemeinsam genutztem Codeimplements: „Ich kann das, was dies tut“ – erzwingt einen Vertrag mit benutzerdefinierter Logik- Sie können nur eine Klasse erweitern, aber mehrere Schnittstellen implementieren
Wählen Sie extends für echte Eltern-Kind-Beziehungen, bei denen Verhalten geerbt werden soll. Wählen Sie implements, wenn Sie Flexibilität benötigen oder einen Vertrag erzwingen möchten, ohne die Implementierung zu teilen.
Probier es selbst
import 'worker.dart';
void main() {
// TODO: Erstelle einen OfficeWorker namens 'Alice' in der Abteilung 'Marketing'
// TODO: Erstelle einen RobotWorker mit dem Modell 'RX-7'
// TODO: Rufe für den Büroangestellten work() und dann takeBreak() auf
// TODO: Gib eine Leerzeile aus
// TODO: Rufe für den RobotWorker work() und dann takeBreak() auf
}
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