Command, Chain of Responsibility and Template Method
Behavioral patterns manage communication and responsibilities between objects. Command encapsulates requests as objects (undo/redo), Chain of Responsibility passes requests along a chain of handlers (middleware), and Template Method defines algorithm skeletons with customizable steps.
🎯 What You Will Learn
- Command pattern: encapsulating actions as objects
- Implementing undo/redo with Command
- Chain of Responsibility: chain of handlers
- Template Method: algorithms with hook points
Command Pattern
The Command pattern encapsulates a request as an object, allowing you to parameterize methods with operations, queue requests, and support undoable operations (undo/redo).
// Command interface
interface Command {{ '{' }}
execute(): void;
undo(): void;
{{ '}' }}
// Receiver: the object that performs the actual action
class Light {{ '{' }}
private isOn: boolean = false;
turnOn(): void {{ '{' }}
this.isOn = true;
console.log("💡 Light turned on");
{{ '}' }}
turnOff(): void {{ '{' }}
this.isOn = false;
console.log("🌑 Light turned off");
{{ '}' }}
getState(): boolean {{ '{' }}
return this.isOn;
{{ '}' }}
{{ '}' }}
// Concrete 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: executes commands
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();
{{ '}' }}
{{ '}' }}
{{ '}' }}
// Usage
const light = new Light();
const remote = new RemoteControl();
remote.executeCommand(new TurnOnCommand(light)); // "💡 Light turned on"
remote.executeCommand(new TurnOffCommand(light)); // "🌑 Light turned off"
remote.undo(); // "💡 Light turned on" (undoes the turn off)
Command with Full Undo/Redo
Advanced implementation with multiple undo/redo operations:
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 = []; // Clear redo stack on new action
{{ '}' }}
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);
{{ '}' }}
{{ '}' }}
{{ '}' }}
// Usage
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
The Chain of Responsibility allows multiple objects to handle a request without the sender knowing which one will handle it. The request passes along a chain until someone handles it.
// Abstract 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(`❌ No handler for: 






