1. The Hook (The "Byte-Sized" Intro)
- In a Nutshell: Memento = save/restore object state (undo/redo, checkpoints), Visitor = add operations to object structure without modifying classes (tax calculator for employees), Interpreter = interpret language grammar (regex, SQL parser).
- Benefits: State management (Memento), extensibility (Visitor), language parsing (Interpreter).
- Use: Memento for undo functionality, Visitor for operations on complex structures, Interpreter for DSLs!
Memento = game save points (save progress, load later). Visitor = health inspector (visits restaurant, performs inspection without changing restaurant). Interpreter = language translator (parse sentence structure, interpret meaning)!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- Memento: Photo snapshot (capture moment, restore later)
- Visitor: Tourist guide (visits sites, performs actions)
- Interpreter: Grammar checker (parse sentences)
3. Technical Mastery (The "Deep Dive")
java
// ===========================================
// 1. MEMENTO PATTERN
// ===========================================
// Memento (state holder)
class EditorMemento {
private final String content;
EditorMemento(String content) {
this.content = content;
}
String getContent() {
return content;
}
}
// Originator
class TextEditor {
private String content = "";
void write(String text) {
content += text;
}
String getContent() {
return content;
}
// Save state
EditorMemento save() {
return new EditorMemento(content);
}
// Restore state
void restore(EditorMemento memento) {
content = memento.getContent();
}
}
// Caretaker
class History {
private Stack<EditorMemento> history = new Stack<>();
void push(EditorMemento memento) {
history.push(memento);
}
EditorMemento pop() {
return history.isEmpty() ? null : history.pop();
}
}
// Usage:
TextEditor editor = new TextEditor();
History history = new History();
editor.write("Hello ");
history.push(editor.save() ); // Save state
editor.write("World");
System.out.println(editor.getContent()); // Hello World
editor.restore(history.pop()); // Undo!
System.out.println(editor.getContent()); // Hello
// ===========================================
// 2. VISITOR PATTERN
// ===========================================
// Element interface
interface Employee {
void accept(Visitor visitor);
}
// Concrete elements
class Manager implements Employee {
private String name;
private double salary;
Manager(String name, double salary) {
this.name = name;
this.salary = salary;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
String getName() { return name; }
double getSalary() { return salary; }
}
class Developer implements Employee {
private String name;
private double salary;
Developer(String name, double salary) {
this.name = name;
this.salary = salary;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
String getName() { return name; }
double getSalary() { return salary; }
}
// Visitor interface
interface Visitor {
void visit(Manager manager);
void visit(Developer developer);
}
// Concrete visitor
class SalaryCalculator implements Visitor {
private double totalSalary = 0;
public void visit(Manager manager) {
double bonus = manager.getSalary() * 0.2; // 20% bonus
totalSalary += manager.getSalary() + bonus;
}
public void visit(Developer developer) {
double bonus = developer.getSalary() * 0.1; // 10% bonus
totalSalary += developer.getSalary() + bonus;
}
double getTotalSalary() {
return totalSalary;
}
}
// Usage:
List<Employee> employees = List.of(
new Manager("Alice", 10000),
new Developer("Bob", 8000)
);
SalaryCalculator calculator = new SalaryCalculator();
for (Employee emp : employees) {
emp.accept(calculator);
}
System.out.println("Total: $" + calculator.getTotalSalary());
// ===========================================
// 3. INTERPRETER PATTERN
// ===========================================
// Expression interface
interface Expression {
boolean interpret(String context);
}
// Terminal expression
class TerminalExpression implements Expression {
private String data;
TerminalExpression(String data) {
this.data = data;
}
public boolean interpret(String context) {
return context.contains(data);
}
}
// Non-terminal expressions
class OrExpression implements Expression {
private Expression expr1;
private Expression expr2;
OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
public boolean interpret(String context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
class AndExpression implements Expression {
private Expression expr1;
private Expression expr2;
AndExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
public boolean interpret(String context) {
return expr1.interpret(context) && expr2.interpret(context);
}
}
// Usage (interpret rule: "Alice OR Bob")
Expression alice = new TerminalExpression("Alice");
Expression bob = new TerminalExpression("Bob");
Expression rule = new OrExpression(alice, bob);
System.out.println(rule.interpret("Alice is here")); // true
System.out.println(rule.interpret("Bob is here")); // true
System.out.println(rule.interpret("Carol is here")); // false5. The Comparison & Decision Layer
| Pattern | Use When |
|---|---|
| Memento | Save/restore state (undo/redo, checkpoints) |
| Visitor | Add operations to structure without modifying classes |
| Interpreter | Parse DSL, implement grammar |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "Why use Visitor pattern?" Answer: Add operations without modifying classes (Open/Closed Principle)!
java
// Without Visitor: Need to modify each class
class Employee {
void calculateSalary() { /* ... */ }
void calculateTax() { /* ... */ } // Add new operation = modify class!
}
// With Visitor: Add operation without modifying Employee
class TaxCalculator implements Visitor {
void visit(Manager m) { /* tax logic */ }
void visit(Developer d) { /* tax logic */ }
}
// No need to modify Manager or Developer!Pro-Tip: Memento for game saves:
java
// Game state
class GameState {
int level, lives, score;
Memento save() {
return new Memento(level, lives, score);
}
void load(Memento m) {
this.level = m.level;
this.lives = m.lives;
this.score = m.score;
}
}
// Save game
Memento checkpoint = game.save();
// Player dies...
game.load(checkpoint); // Restore from save!