Menu
Coddy logo textTech

Komposition vs. Vererbung

Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy. Lektion 47 von 87.

Vererbung stellt eine „ist-ein“-Beziehung her: Ein Dog ist ein Animal. Aber was ist, wenn eine Klasse Funktionalität von etwas benötigt, das sie nicht ist? Hier kommt die Komposition ins Spiel, die stattdessen eine „hat-ein“-Beziehung herstellt.

Bei der Komposition enthält eine Klasse Instanzen anderer Klassen als Felder, anstatt sie zu erweitern:

// Vererbungsansatz: Car IS an Engine (ergibt keinen Sinn)
class Car extends Engine { }

// Kompositionsansatz: Car HAS an Engine (ergibt Sinn)
class Car {
    private Engine engine;
    
    public Car(Engine engine) {
        this.engine = engine;
    }
    
    public void start() {
        engine.ignite();
    }
}

Komposition bietet mehrere Vorteile. Du kannst das zusammengesetzte Objekt zur Laufzeit ändern, beispielsweise indem du Motoren austauschst.

Du kannst auch Verhaltensweisen aus mehreren Klassen kombinieren, was die Vererbung in Java nicht erlaubt. Die zusammengesetzte Klasse stellt nur die Methoden bereit, für die sie sich entscheidet, und bietet dadurch eine bessere Kapselung.

Eine praktische Richtlinie: Verwende Vererbung, wenn eine echte „ist-ein“-Beziehung besteht und die Unterklasse tatsächlich eine spezialisierte Version der übergeordneten Klasse darstellt.

Verwende Komposition, wenn du die Funktionalität einer anderen Klasse nutzen musst, ohne von diesem Typ zu sein. Viele erfahrene Entwickler folgen dem Prinzip: „Komposition vor Vererbung bevorzugen“, weil dies zu flexiblerem und leichter wartbarem Code führt.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Computersystem mithilfe von Komposition, um die „has-a“-Beziehung zu veranschaulichen. Anstatt dass ein Computer von seinen Komponenten erbt (was keinen Sinn ergeben würde), wird dein Computer die Teile enthalten, die er für seine Funktion benötigt.

Du wirst deinen Code auf drei Dateien verteilen:

  • Processor.java: Erstelle eine Klasse, die eine CPU repräsentiert. Ein Processor besitzt zwei private Felder: brand (String) und speedGHz (double). Füge einen Konstruktor hinzu, der beide Felder initialisiert, sowie Getter-Methoden für jedes Feld. Füge eine process()-Methode hinzu, die einen String zurückgibt: [brand] processing at [speedGHz] GHz
  • Memory.java: Erstelle eine Klasse, die RAM repräsentiert. Ein Memory besitzt zwei private Felder: type (String, etwa "DDR4" oder "DDR5") und sizeGB (int). Füge einen Konstruktor, Getter und eine load()-Methode hinzu, die Folgendes zurückgibt: Loading [sizeGB]GB [type] memory
  • Computer.java: Hier zeigt sich die Stärke der Komposition! Deine Computer-Klasse sollte einen Processor und einen Memory als private Felder besitzen. Sie erweitert diese nicht, sondern enthält sie. Füge einen Konstruktor hinzu, der beide Komponenten entgegennimmt. Füge eine boot()-Methode hinzu, die einen mehrzeiligen String zurückgibt, der das Starten des Computers durch die Verwendung seiner Komponenten zeigt:
    Booting computer...
    [processor.process() result]
    [memory.load() result]
    System ready!
    Füge außerdem eine getSpecs()-Methode hinzu, die Folgendes zurückgibt: Specs: [processor brand] CPU, [memory sizeGB]GB [memory type]
  • Main.java: Erwecke dein zusammengesetztes System zum Leben! Du erhältst vier Eingaben: die Marke des Prozessors (String), die Geschwindigkeit des Prozessors (double), den Speichertyp (String) und die Speichergröße (int).

    Erstelle mit diesen Werten einen Processor und einen Memory und füge sie anschließend zu einem Computer zusammen. Gib das Ergebnis des Aufrufs von boot() aus und gib danach das Ergebnis von getSpecs() aus.

Du erhältst vier Eingaben in dieser Reihenfolge: Prozessormarke, Prozessorgeschwindigkeit (GHz), Speichertyp und Speichergröße (GB).

Beachte, wie der Computer Arbeit an seine Komponenten delegiert, anstatt zu versuchen, selbst eine davon zu sein. Das ist die Stärke der Komposition! Der Computer kann jeden Processor oder Memory verwenden, den du ihm übergibst, wodurch das Design flexibel und realistisch wird.

Probier es selbst

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Eingaben lesen
        String processorBrand = scanner.nextLine();
        double processorSpeed = Double.parseDouble(scanner.nextLine());
        String memoryType = scanner.nextLine();
        int memorySize = Integer.parseInt(scanner.nextLine());
        
        // TODO: Erstelle einen Processor mit der Marke und der Geschwindigkeit
        
        // TODO: Erstelle einen Memory mit dem Typ und der Größe
        
        // TODO: Erstelle einen Computer durch Zusammensetzen von Processor und Memory
        
        // TODO: Gib das Ergebnis von boot() aus
        
        // TODO: Gib das Ergebnis von getSpecs() 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-Java-Compiler