Was ist ein Kompositum?

Ein Kompositum (engl. compoite) ist ein Entwurfsmuster aus der Gruppe der Strukturmuster, das zu den von der sog. Viererbande (Gang of Four, GoF) klassifizierten gehört. Es wird zur Darstellung von Teil-Ganzes-Hierarchien verwendet.

In Komposita sind Objekte organisiert, die Einzelobjekte oder Mengen von Einzelobjekten enthalten können, wobei beide gleich behandelt werden. Ein Beispiel sind Baumstrukturen, etwa von hierarchischen Dateisystemdarstellungen, in denen einzelne Dateien und Verzeichnisse in übergeordneten Verzeichnissen organisiert sind.

import java.util.ArrayList;
import java.util.List;

interface Verpackung {
    void enthalte();
}

class Kasten implements Verpackung {

    private List<Verpackung> verpackungen = new ArrayList<Verpackung>();

    @Override
    public void enthalte() {
        for (Verpackung v : verpackungen) {
            v.enthalte();
        }
    }

    public void legeRein(Verpackung v) {
        verpackungen.add(v);
    }

    public void nimmRaus(Verpackung v) {
        verpackungen.remove(v);
    }
}

class Schachtel implements Verpackung {

    @Override
    public void enthalte() {
        System.out.println("Schachtel");
    }
}

class Dose implements Verpackung {

    @Override
    public void enthalte() {
        System.out.println("Dose");
    }
}

public class Kompositum {

    public static void main(String[] args) {
        Schachtel schachtel1 = new Schachtel(), schachtel2 = new Schachtel(),
                schachtel3 = new Schachtel(), schachtel4 = new Schachtel();

        Dose dose1 = new Dose(), dose2 = new Dose(), dose3 = new Dose();
        
        Kasten kasten1 = new Kasten(), kasten2 = new Kasten();
        
        kasten1.legeRein(schachtel1);
        kasten1.legeRein(schachtel2);
        kasten2.legeRein(schachtel3);
        kasten2.legeRein(schachtel4);
        kasten2.legeRein(dose1);
        kasten2.legeRein(dose2);
        kasten2.legeRein(dose3);
        
        Kasten truhe = new Kasten();
        truhe.legeRein(kasten1);
        truhe.legeRein(kasten2);
        
        truhe.enthalte();
    }
}

Im Beispiel sind ein Interface und vier Klassen deklariert. Neben der die main()-Methode enthaltenden Startklasse existieren zwei prinzipiell gleich aufgebaute Klassen Schachtel und Dose, die die prinzipielle Erweiterbarkeit des Musters zeigen. Des Weiteren existiert eine Klasse Kasten. Alle drei implementieren das Interface Verpackung und konkretisieren die Methode enthalte(). Kasten jedoch ist in der Lage, beliebige Objekte eines Typs, der Verpackung implementiert, in einer Liste zu speichern und deren Methoden enthalte() aufzurufen. Dies geschieht dadurch, dass die in der Liste gespeicherten Objekte in einer Schleife aufgerufen werden.

In main() werden mehrere Objekte der Verpackung implementierenden Klassen gebildet. Die Objekte der 'Einzelklassen' Dose und Schachtel werden anschließend in den Listen der Kasten-Objekte gespeichert. Alle Elemente werden schließlich einem einzigen Kasten-Objekt hinzugefügt und dessen Methode enthalte() aufgerufen. Als Ergebnis werden alle beteiligten enthalte()-Methoden aufgerufen, ohne dass von außen erkenntlich ist, aus welcher Klasse sie stammen.