1. The Hook (The "Byte-Sized" Intro)
- In a Nutshell: Behavioral patterns define object communication. Observer = one-to-many notification (YouTube subscribers), Strategy = encapsulate algorithms, switch at runtime (payment methods), Command = encapsulate request as object (undo/redo), Template Method = algorithm skeleton, subclasses fill steps (recipe framework).
- Benefits: Loose coupling, flexibility, extensibility.
- Use: Observer for event systems, Strategy for interchangeable algorithms, Command for queuing/undo, Template Method for algorithm frameworks!
Observer = news subscription (1 publisher, many subscribers). Strategy = navigation (walk/drive/fly, choose at runtime). Command = restaurant order (waiter → kitchen). Template Method = cooking recipe (heat→add ingredients→serve, specifics vary)!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- Observer: Newsletter (one sender, many receivers)
- Strategy: Payment methods (credit card, PayPal, cash)
- Command: TV remote button (button → action)
- Template Method: Assembly line (steps fixed, details vary)
3. Technical Mastery (The "Deep Dive")
java
// ===========================================
// 1. OBSERVER PATTERN
// ===========================================
// Observer interface
interface Observer {
void update(String message);
}
// Subject (Observable)
class NewsAgency {
private List<Observer> observers = new ArrayList<>();
private String news;
void addObserver(Observer observer) {
observers.add(observer);
}
void removeObserver(Observer observer) {
observers.remove(observer);
}
void setNews(String news) {
this.news = news;
notifyObservers();
}
private void notifyObservers() {
for (Observer observer : observers) {
observer.update(news);
}
}
}
// Concrete observers
class EmailSubscriber implements Observer {
private String email;
EmailSubscriber(String email) {
this.email = email;
}
public void update(String message) {
System.out.println("Email to " + email + ": " + message);
}
}
// Usage:
NewsAgency agency = new NewsAgency();
agency.addObserver(new EmailSubscriber("alice@example.com"));
agency.addObserver(new EmailSubscriber("bob@example.com"));
agency.setNews("Breaking news!"); // Notifies all subscribers
// ===========================================
// 2. STRATEGY PATTERN
// ===========================================
// Strategy interface
interface PaymentStrategy {
void pay(int amount);
}
// Concrete strategies
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid $" + amount + " with credit card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid $" + amount + " with PayPal");
}
}
class CashPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid $" + amount + " with cash");
}
}
// Context
class ShoppingCart {
private PaymentStrategy paymentStrategy;
void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
// Usage:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100);
cart.setPaymentStrategy(new PayPalPayment()); // Switch strategy!
cart.checkout(50);
// ===========================================
// 3. COMMAND PATTERN
// ===========================================
// Command interface
interface Command {
void execute();
void undo();
}
// Receiver
class Light {
void turnOn() {
System.out.println("Light ON");
}
void turnOff() {
System.out.println("Light OFF");
}
}
// Concrete commands
class LightOnCommand implements Command {
private Light light;
LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn();
}
public void undo() {
light.turnOff();
}
}
class LightOffCommand implements Command {
private Light light;
LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOff();
}
public void undo() {
light.turnOn();
}
}
// Invoker
class RemoteControl {
private Command command;
private Stack<Command> history = new Stack<>();
void setCommand(Command command) {
this.command = command;
}
void pressButton() {
command.execute();
history.push(command);
}
void pressUndo() {
if (!history.isEmpty()) {
Command lastCommand = history.pop();
lastCommand.undo();
}
}
}
// Usage:
Light light = new Light();
RemoteControl remote = new RemoteControl();
remote.setCommand(new LightOnCommand(light));
remote.pressButton(); // Light ON
remote.pressUndo(); // Light OFF (undo!)
// ===========================================
// 4. TEMPLATE METHOD PATTERN
// ===========================================
// Abstract class with template method
abstract class DataProcessor {
// Template method (final = can't override)
final void process() {
loadData();
processData();
saveData();
}
// Steps (some abstract, some with default implementation)
abstract void loadData();
abstract void processData();
void saveData() {
System.out.println("Data saved"); // Default implementation
}
}
// Concrete classes
class CSVProcessor extends DataProcessor {
void loadData() {
System.out.println("Loading CSV");
}
void processData() {
System.out.println("Processing CSV");
}
}
class XMLProcessor extends DataProcessor {
void loadData() {
System.out.println("Loading XML");
}
void processData() {
System.out.println("Processing XML");
}
@Override
void saveData() {
System.out.println("Saving XML (custom)");
}
}
// Usage:
DataProcessor csv = new CSVProcessor();
csv.process(); // Calls template method
DataProcessor xml = new XMLProcessor();
xml.process();5. The Comparison & Decision Layer
| Pattern | Use When |
|---|---|
| Observer | One-to-many notifications (event systems, MVC) |
| Strategy | Interchangeable algorithms (sorting, compression) |
| Command | Encapsulate requests (undo/redo, queueing) |
| Template Method | Algorithm skeleton with varying steps (frameworks) |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "Strategy vs Template Method?" Answer:
- Strategy: Composition-based, choose algorithm at runtime
- Template Method: Inheritance-based, subclass provides implementation
java
// Strategy: Runtime selection
cart.setPaymentStrategy(new PayPalPayment()); // Can change!
// Template Method: Compile-time selection
DataProcessor processor = new CSVProcessor(); // Fixed at creationPro-Tip: Observer in Java:
java
// Built-in Observer (deprecated, but concept remains)
// Modern: Use PropertyChangeListener, EventListener
// JavaFX uses Observer for properties
StringProperty name = new SimpleStringProperty();
name.addListener((obs, oldVal, newVal) -> {
System.out.println("Changed: " + oldVal + " → " + newVal);
});
name.set("Alice"); // Notifies listener!