Menu
Coddy logo textTech

Dekorierermuster

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

Das Dekorator-Muster ist ein strukturelles Entwurfsmuster, mit dem du Objekten neue Verhaltensweisen hinzufügen kannst, indem du sie in spezielle Objekte einhüllst, die als Dekoratoren bezeichnet werden. Im Gegensatz zur Vererbung, die Verhalten zur Kompilierungszeit hinzufügt, erweitern Dekoratoren die Funktionalität dynamisch zur Laufzeit, ohne die ursprüngliche Klasse zu verändern.

Stell dir ein Café vor, in dem du mit einem einfachen Kaffee beginnst und Extras wie Milch, Zucker oder Schlagsahne hinzufügen kannst. Jede Ergänzung umhüllt den ursprünglichen Kaffee und fügt seine Kosten und Beschreibung hinzu. Das Muster verwendet eine gemeinsame Schnittstelle, sodass dekorierte Objekte genauso wie das Original behandelt werden können:

interface Coffee {
    String getDescription();
    double getCost();
}

class SimpleCoffee implements Coffee {
    public String getDescription() {
        return "Simple Coffee";
    }
    public double getCost() {
        return 2.0;
    }
}

abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}

class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }
    
    public double getCost() {
        return coffee.getCost() + 0.5;
    }
}

Der Decorator enthält eine Referenz auf das umschlossene Objekt und delegiert Aufrufe an dieses, während er sein eigenes Verhalten hinzufügt. Du kannst mehrere Decorators stapeln, um Funktionen zu kombinieren:

Coffee order = new SimpleCoffee();
order = new MilkDecorator(order);
order = new SugarDecorator(order);

System.out.println(order.getDescription());  // Simple Coffee, Milk, Sugar
System.out.println(order.getCost());         // 2.75

Das Dekorierer-Muster kommt besonders dann zur Geltung, wenn du Objekten Verantwortlichkeiten hinzufügen musst, ohne eine Flut von Unterklassen zu erzeugen. Jeder Dekorierer ist unabhängig, sodass du sie frei kombinieren kannst, um genau die Kombination von Verhaltensweisen zu erstellen, die du benötigst.

challenge icon

Aufgabe

Einfach

Lass uns ein Benachrichtigungssystem mit dem Decorator Pattern erstellen! Du erstellst eine grundlegende Benachrichtigung, die mit verschiedenen Zustellkanälen, E-Mail-Benachrichtigungen, SMS-Benachrichtigungen und Push-Benachrichtigungen erweitert werden kann, indem Decorator-Objekte ineinander verschachtelt werden. Dies bildet reale Systeme nach, in denen eine einzelne Nachricht möglicherweise gleichzeitig über mehrere Kanäle versendet werden muss.

Du wirst deinen Code auf vier Dateien verteilen:

  • Notifier.java: Define die Notifier-Schnittstelle, die als component-Schnittstelle für dein Decorator Pattern dient. Sie sollte eine Methode send(String message) Declare, die das Senden von Benachrichtigungen übernimmt.
  • BasicNotifier.java: Create die konkrete component-Klasse, die Notifier implements. Dies stellt die einfachste Form einer Benachrichtigung dar: eine In-App-Benachrichtigung. Wenn send aufgerufen wird, sollte In-App: [message] ausgegeben werden.
  • NotifierDecorators.java: Erstelle hier deine Decorator hierarchy. Beginne mit einer abstract-Klasse NotifierDecorator, die Notifier implements und eine Referenz auf ein umschlossenes Notifier-Objekt enthält, das über ihren constructor übergeben wird.

    Erstelle dann drei konkrete Decorator-Klassen, die NotifierDecorator erweitern:

    EmailDecorator – Wenn send aufgerufen wird, delegiert es zunächst an den umschlossenen Notifier und gibt anschließend Email: [message] aus.

    SMSDecorator – Wenn send aufgerufen wird, delegiert es zunächst an den umschlossenen Notifier und gibt anschließend SMS: [message] aus.

    PushDecorator – Wenn send aufgerufen wird, delegiert es zunächst an den umschlossenen Notifier und gibt anschließend Push: [message] aus.

  • Main.java: Führe dein Decorator-System zusammen! Du erhältst zwei Eingaben: die Benachrichtigungsnachricht (String) und eine durch Kommas getrennte Liste der hinzuzufügenden Kanäle (String), zum Beispiel "email,sms" oder "push,email,sms".

    Beginne mit einem BasicNotifier. Umschließe ihn dann basierend auf der Kanaleingabe mit den appropriate Decorators in der Reihenfolge, in der sie erscheinen. Gültige Kanalnamen sind email, sms und push.

    Rufe schließlich send mit deiner Nachricht auf dem fully dekorierten Notifier auf.

Du erhältst zwei Eingaben in dieser Reihenfolge: die zu sendende Nachricht (String) und die zu aktivierenden Kanäle (String, durch Kommas getrennt).

Bei den Eingaben Server is down! und email,push würde deine Ausgabe beispielsweise folgendermaßen aussehen:

In-App: Server is down!
Email: Server is down!
Push: Server is down!

Beachte, wie jeder Decorator sein eigenes Verhalten hinzufügt und dabei die ursprüngliche Benachrichtigung bewahrt. Die Reihenfolge des Umschließens bestimmt die Reihenfolge der Ausgabe: Das innerste component (BasicNotifier) wird zuerst ausgeführt, danach fügt jeder Decorator seine Ebene hinzu. Du kannst beliebige Kombinationen von Kanälen kombinieren, ohne separate Klassen für jede Kombination erstellen zu müssen!

Probier es selbst

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Lese die zu sendende Nachricht
        String message = scanner.nextLine();
        
        // Lese die kommagetrennte Liste der Kanäle (z. B. "email,sms" oder "push,email,sms")
        String channelsInput = scanner.nextLine();
        
        // TODO: Beginne mit einem BasicNotifier
        
        // TODO: Teile die Kanaleingabe am Komma auf
        
        // TODO: Gehe jeden Kanal durch und umhülle den Notifier mit dem entsprechenden Decorator
        // Gültige Kanäle sind: "email", "sms", "push"
        
        // TODO: Rufe send auf dem vollständig dekorierten Notifier mit der Nachricht auf
        
    }
}
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