Command, Chain of Responsibility und Template Method
Verhaltensmuster verwalten die Kommunikation und Verantwortlichkeiten zwischen Objekten. Command kapselt Anfragen als Objekte (Undo/Redo), Chain of Responsibility leitet Anfragen entlang einer Kette von Handlern weiter (Middleware), und Template Method definiert Algorithmus-Skelette mit anpassbaren Schritten.
Was Sie lernen werden
- Command-Pattern: Aktionen als Objekte kapseln
- Undo/Redo mit Command implementieren
- Chain of Responsibility: Kette von Handlern
- Template Method: Algorithmen mit Erweiterungspunkten
Command-Pattern
Das Command-Pattern kapselt eine Anfrage als Objekt und ermöglicht es, Methoden mit Operationen zu parametrisieren, Anfragen in die Warteschlange zu stellen und rückgängig machbare Operationen (Undo/Redo) zu unterstützen.
// Command-Schnittstelle
interface Command {
execute(): void;
undo(): void;
}
// Receiver: Objekt, das die eigentliche Aktion ausführt
class Light {
private isOn: boolean = false;
turnOn(): void {
this.isOn = true;
console.log("Licht eingeschaltet");
}
turnOff(): void {
this.isOn = false;
console.log("Licht ausgeschaltet");
}
getState(): boolean {
return this.isOn;
}
}
// Konkrete Commands
class TurnOnCommand implements Command {
constructor(private light: Light) {}
execute(): void {
this.light.turnOn();
}
undo(): void {
this.light.turnOff();
}
}
class TurnOffCommand implements Command {
constructor(private light: Light) {}
execute(): void {
this.light.turnOff();
}
undo(): void {
this.light.turnOn();
}
}
// Invoker: führt die Commands aus
class RemoteControl {
private history: Command[] = [];
executeCommand(command: Command): void {
command.execute();
this.history.push(command);
}
undo(): void {
const command = this.history.pop();
if (command) {
command.undo();
}
}
}
// Verwendung
const light = new Light();
const remote = new RemoteControl();
remote.executeCommand(new TurnOnCommand(light)); // "Licht eingeschaltet"
remote.executeCommand(new TurnOffCommand(light)); // "Licht ausgeschaltet"
remote.undo(); // "Licht eingeschaltet" (macht das Ausschalten rückgängig)
Command mit vollständigem Undo/Redo
Fortgeschrittene Implementierung mit mehrfachem Undo/Redo:
class TextEditor {
private content: string = "";
getContent(): string {
return this.content;
}
setContent(content: string): void {
this.content = content;
}
append(text: string): void {
this.content += text;
}
delete(length: number): void {
this.content = this.content.slice(0, -length);
}
}
class AppendCommand implements Command {
constructor(
private editor: TextEditor,
private text: string
) {}
execute(): void {
this.editor.append(this.text);
}
undo(): void {
this.editor.delete(this.text.length);
}
}
class DeleteCommand implements Command {
private deletedText: string = "";
constructor(
private editor: TextEditor,
private length: number
) {}
execute(): void {
const content = this.editor.getContent();
this.deletedText = content.slice(-this.length);
this.editor.delete(this.length);
}
undo(): void {
this.editor.append(this.deletedText);
}
}
class CommandManager {
private history: Command[] = [];
private redoStack: Command[] = [];
execute(command: Command): void {
command.execute();
this.history.push(command);
this.redoStack = []; // Redo-Stapel bei neuer Aktion leeren
}
undo(): void {
const command = this.history.pop();
if (command) {
command.undo();
this.redoStack.push(command);
}
}
redo(): void {
const command = this.redoStack.pop();
if (command) {
command.execute();
this.history.push(command);
}
}
}
// Verwendung
const editor = new TextEditor();
const manager = new CommandManager();
manager.execute(new AppendCommand(editor, "Hello "));
manager.execute(new AppendCommand(editor, "World"));
console.log(editor.getContent()); // "Hello World"
manager.undo();
console.log(editor.getContent()); // "Hello "
manager.redo();
console.log(editor.getContent()); // "Hello World"
Chain of Responsibility-Pattern
Das Chain of Responsibility-Pattern ermöglicht es mehreren Objekten, eine Anfrage zu bearbeiten, ohne dass der Absender weiß, welches sie bearbeiten wird. Die Anfrage wird entlang einer Kette weitergeleitet, bis jemand sie bearbeitet.
// Abstrakter Handler
abstract class Handler {
protected next: Handler | null = null;
setNext(handler: Handler): Handler {
this.next = handler;
return handler; // Fluent Interface
}
handle(request: string): void {
if (this.canHandle(request)) {
this.process(request);
} else if (this.next) {
this.next.handle(request);
} else {
console.log(`Kein Handler für: 






