Menu
CoddyTech

Komposition vs. Vererbung

Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy. Lektion 82 von 110.

Du hast gelernt, dass Vererbung eine „ist-ein“-Beziehung herstellt – ein Dog ist ein Animal. Es gibt jedoch noch einen weiteren leistungsstarken Ansatz: Komposition, die eine „hat-ein“-Beziehung herstellt. Anstatt Verhalten zu erben, enthält eine Klasse Instanzen anderer Klassen und delegiert Aufgaben an sie.

Stell dir eine Klasse Car vor. Bei Vererbung könntest du versuchen, eine Klasse Engine zu erweitern – aber ein Auto ist kein Motor, es hat einen Motor:

class Engine {
  void start() => print('Engine started');
}

class Car {
  final Engine _engine = Engine();  // Komposition: Car HAT eine Engine
  
  void start() {
    _engine.start();  // An die Engine delegieren
    print('Car is ready to drive');
  }
}

void main() {
  var car = Car();
  car.start();
}

Der entscheidende Vorteil der Komposition ist die Flexibilität. Bei Vererbung bist du an eine einzige Elternklasse gebunden. Bei Komposition kannst du mehrere Komponenten kombinieren und sie sogar zur Laufzeit austauschen:

class ElectricEngine {
  void start() => print('Electric motor humming');
}

class HybridCar {
  Engine? _gasEngine;
  ElectricEngine? _electricEngine;
  
  HybridCar({bool useElectric = false}) {
    if (useElectric) {
      _electricEngine = ElectricEngine();
    } else {
      _gasEngine = Engine();
    }
  }
}

Eine gängige Richtlinie lautet: „Komposition vor Vererbung bevorzugen“. Verwende Vererbung, wenn eine echte „Ist-ein“-Beziehung besteht und du Polymorphie benötigst. Verwende Komposition, wenn du Verhalten ohne enge Kopplung wiederverwenden möchtest oder wenn ein Objekt Fähigkeiten aus mehreren Quellen benötigt.

challenge icon

Aufgabe

Einfach

Lass uns mithilfe von Komposition ein Computersystem erstellen! Statt zu versuchen, einen Computer von seinen Bestandteilen erben zu lassen, erstellst du separate Komponentenklassen und setzt sie zusammen – denn ein Computer hat eine CPU und hat Speicher; er ist keine CPU und kein Speicher.

Du organisierst deinen Code in drei Dateien:

  • components.dart: Erstelle zwei Komponentenklassen, die Computerteile darstellen:
    • Eine CPU-Klasse mit einem String brand und einem double speedGHz. Füge eine process()-Methode hinzu, die einen String zurückgibt: [brand] processing at [speedGHz]GHz
    • Eine Memory-Klasse mit einem int sizeGB. Füge eine load()-Methode hinzu, die einen String zurückgibt: Loading [sizeGB]GB of data
  • computer.dart: Erstelle eine Computer-Klasse, die mithilfe von Komposition die Komponenten kombiniert. Dein Computer sollte:
    • Ein Feld String name haben
    • Eine CPU- und eine Memory-Instanz enthalten (Komposition – der Computer HAT diese Teile)
    • Alle erforderlichen Werte über seinen Konstruktor entgegennehmen, um beide Komponenten intern zu erstellen
    • Eine boot()-Methode haben, die Aufrufe an beide Komponenten delegiert und drei Zeilen ausgibt: den Namen des Computers gefolgt von starting..., dann das Ergebnis der process-Methode der CPU und anschließend das Ergebnis der load-Methode von Memory
    • Eine specs()-Methode haben, die einen String zurückgibt, der das System beschreibt: [name]: [brand] [speedGHz]GHz, [sizeGB]GB RAM
  • main.dart: Importiere deine Dateien und zeige Komposition in Aktion:
    • Erstelle einen Computer namens Workstation mit einer Intel-CPU, die mit 3.5 GHz läuft, und 16 GB Speicher
    • Rufe die Methode boot() auf
    • Gib das Ergebnis von specs() aus

Beachte, dass die Computer-Klasse weder CPU noch Memory erweitert – sie enthält sie und delegiert Aufgaben an sie. Das ist die „hat-eine“-Beziehung, die durch Komposition entsteht!

Erwartete Ausgabe:

Workstation starting...
Intel processing at 3.5GHz
Loading 16GB of data
Workstation: Intel 3.5GHz, 16GB RAM

Probier es selbst

import 'computer.dart';

void main() {
  // TODO: Erstelle einen Computer namens "Workstation" mit:
  // - einer Intel-CPU mit 3.5 GHz
  // - 16 GB Arbeitsspeicher

  // TODO: Rufe die Methode boot() auf

  // TODO: Gib das Ergebnis von specs() aus
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Dart-Compiler