Overview of Design Patterns
A comprehensive guide to the top 20 design patterns in software engineering, categorized by their purpose.
Pattern Categories
| Category | Pattern | Purpose |
|---|---|---|
| Creational | Singleton | Single instance control |
| Factory Method | Object creation via interface | |
| Abstract Factory | Families of related objects | |
| Builder | Step-by-step object construction | |
| Prototype | Clone-based instantiation | |
| Structural | Adapter | Interface compatibility |
| Bridge | Decouple abstraction from implementation | |
| Composite | Tree-like object structures | |
| Decorator | Dynamic behavior addition | |
| Facade | Simplified subsystem interface | |
| Flyweight | Memory optimization via sharing | |
| Proxy | Controlled object access | |
| Behavioral | Observer | State change notification |
| Strategy | Algorithm interchangeability | |
| Command | Request encapsulation | |
| Template Method | Algorithm skeleton | |
| Mediator | Object interaction mediation | |
| Chain of Responsibility | Request passing chain | |
| State | State-dependent behavior | |
| Visitor | Operation separation from structure |
Detailed Patterns
Basics
Ensures a class has only one instance and provides a global point of access to it.
Description
The Singleton pattern is a creational design pattern that restricts a class to a single instance, often used for resources like loggers, thread pools, or configuration managers. It employs a private constructor and a static method to control instantiation, with thread-safety considerations in multi-threaded environments. While powerful, it can introduce global state, potentially complicating testing and scalability.
Structure
Key Components
| Component | Description |
|---|---|
| Static Instance | Holds the single instance. |
| Private Constructor | Prevents external instantiation. |
| Get Instance | Controls access with lazy initialization. |
Examples
Java (Basic)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
} Java (Thread-Safe)
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
} Basics
Defines an interface for creating objects, letting subclasses decide which class to instantiate.
Description
The Factory Method pattern is a creational pattern that delegates object creation to subclasses. It’s ideal when the exact type of object isn’t known until runtime, promoting flexibility and extensibility. Commonly used in frameworks where clients define custom implementations, it reduces direct dependencies on concrete classes.
Structure
Key Components
| Component | Description |
|---|---|
| Creator | Declares the factory method. |
| Concrete Creator | Implements the factory method. |
| Product | Interface for created objects. |
Examples
Java (Basic)
interface Product {
void use();
}
class ConcreteProduct implements Product {
public void use() { System.out.println("Using product"); }
}
abstract class Creator {
abstract Product factoryMethod();
}
class ConcreteCreator extends Creator {
Product factoryMethod() { return new ConcreteProduct(); }
} Java (Parameterized)
interface Shape {
void draw();
}
class Circle implements Shape {
public void draw() { System.out.println("Drawing Circle"); }
}
class Rectangle implements Shape {
public void draw() { System.out.println("Drawing Rectangle"); }
}
abstract class ShapeCreator {
abstract Shape createShape();
}
class CircleCreator extends ShapeCreator {
Shape createShape() { return new Circle(); }
}
class RectangleCreator extends ShapeCreator {
Shape createShape() { return new Rectangle(); }
} Basics
Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
Description
The Abstract Factory pattern is a creational pattern that groups related objects into families, ensuring compatibility. It’s useful in UI toolkits or cross-platform apps where you need consistent sets of components (e.g., buttons and windows). It abstracts the creation process further than Factory Method by handling multiple product types.
Structure
Key Components
| Component | Description |
|---|---|
| Abstract Factory | Interface for creating product families. |
| Concrete Factory | Implements family creation. |
| Abstract Product | Interfaces for product types. |
Examples
Java (Basic)
interface Button { void render(); }
interface Window { void open(); }
class WinButton implements Button { public void render() { System.out.println("Windows Button"); } }
class WinWindow implements Window { public void open() { System.out.println("Windows Window"); } }
interface GUIFactory {
Button createButton();
Window createWindow();
}
class WinFactory implements GUIFactory {
public Button createButton() { return new WinButton(); }
public Window createWindow() { return new WinWindow(); }
} Java (Extended)
interface Button { void render(); }
interface Window { void open(); }
interface Menu { void show(); }
class MacButton implements Button { public void render() { System.out.println("Mac Button"); } }
class MacWindow implements Window { public void open() { System.out.println("Mac Window"); } }
class MacMenu implements Menu { public void show() { System.out.println("Mac Menu"); } }
interface GUIFactory {
Button createButton();
Window createWindow();
Menu createMenu();
}
class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public Window createWindow() { return new MacWindow(); }
public Menu createMenu() { return new MacMenu(); }
} Basics
Separates the construction of a complex object from its representation, allowing step-by-step creation.
Description
The Builder pattern is a creational pattern for constructing complex objects incrementally. It’s ideal for objects with many optional parameters (e.g., a car with custom features) or when construction logic varies. Unlike Factory, it focuses on the process, not just the product type.
Structure
Key Components
| Component | Description |
|---|---|
| Builder | Interface for construction steps. |
| Concrete Builder | Implements steps and builds product. |
| Director | Orchestrates construction. |
| Product | Resulting complex object. |
Examples
Java (Basic)
class Product {
String partA, partB;
public String toString() { return "Product [A=" + partA + ", B=" + partB + "]"; }
}
interface Builder {
void buildPartA(String partA);
void buildPartB(String partB);
Product getResult();
}
class ConcreteBuilder implements Builder {
private Product product = new Product();
public void buildPartA(String partA) { product.partA = partA; }
public void buildPartB(String partB) { product.partB = partB; }
public Product getResult() { return product; }
}
class Director {
void construct(Builder builder) {
builder.buildPartA("Part A");
builder.buildPartB("Part B");
}
} Java (Fluent)
class Car {
private String engine, wheels;
public void setEngine(String e) { this.engine = e; }
public void setWheels(String w) { this.wheels = w; }
public String toString() { return "Car [Engine=" + engine + ", Wheels=" + wheels + "]"; }
}
class CarBuilder {
private Car car = new Car();
public CarBuilder addEngine(String e) { car.setEngine(e); return this; }
public CarBuilder addWheels(String w) { car.setWheels(w); return this; }
public Car build() { return car; }
}
class Demo {
public static void main(String[] args) {
Car car = new CarBuilder().addEngine("V8").addWheels("Alloy").build();
System.out.println(car);
}
} Basics
Creates new objects by copying an existing instance (prototype), avoiding subclassing.
Description
The Prototype pattern is a creational pattern that uses cloning to instantiate objects, ideal when object creation is costly or complex (e.g., database-loaded configs). It reduces initialization overhead and supports dynamic object types via a registry.
Structure
Key Components
| Component | Description |
|---|---|
| Prototype | Interface with clone method. |
| Concrete Prototype | Implements cloning. |
| Client | Requests clones. |
Examples
Java (Basic)
interface Prototype extends Cloneable {
Prototype clone();
}
class ConcretePrototype implements Prototype {
private String field;
public ConcretePrototype(String field) { this.field = field; }
public Prototype clone() {
try { return (Prototype) super.clone(); }
catch (CloneNotSupportedException e) { return null; }
}
public String toString() { return field; }
} Java (With Registry)
interface Prototype extends Cloneable {
Prototype clone();
}
class Shape implements Prototype {
private String type;
public Shape(String type) { this.type = type; }
public Prototype clone() {
try { return (Prototype) super.clone(); }
catch (CloneNotSupportedException e) { return null; }
}
public String toString() { return type; }
}
class PrototypeRegistry {
private Map<String, Prototype> prototypes = new HashMap<>();
public void addPrototype(String key, Prototype p) { prototypes.put(key, p); }
public Prototype getPrototype(String key) { return prototypes.get(key).clone(); }
} Basics
Converts the interface of a class into another interface that a client expects.
Description
The Adapter pattern is a structural pattern that bridges incompatible interfaces, allowing classes to work together that otherwise couldn’t. It’s common in legacy system integration or third-party library usage, acting as a wrapper or translator.
Structure
Key Components
| Component | Description |
|---|---|
| Target | Desired interface. |
| Adaptee | Existing incompatible class. |
| Adapter | Wraps adaptee to match target. |
Examples
Java (Class Adapter)
interface Target { void request(); }
class Adaptee { public void specificRequest() { System.out.println("Specific request"); } }
class Adapter extends Adaptee implements Target {
public void request() { specificRequest(); }
} Java (Object Adapter)
interface Target { void request(); }
class Adaptee { public void specificRequest() { System.out.println("Specific request"); } }
class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) { this.adaptee = adaptee; }
public void request() { adaptee.specificRequest(); }
} Basics
Decouples an abstraction from its implementation so the two can vary independently.
Description
The Bridge pattern is a structural pattern that separates interface from implementation, allowing both to evolve separately. It’s useful in graphics libraries or drivers where abstraction (e.g., shape) and implementation (e.g., rendering) need flexibility.
Structure
Key Components
| Component | Description |
|---|---|
| Abstraction | Defines the interface. |
| Implementor | Defines implementation interface. |
| Concrete Implementor | Provides implementation. |
Examples
Java (Basic)
interface Implementor { void operationImpl(); }
class ConcreteImplementor implements Implementor {
public void operationImpl() { System.out.println("Implementation"); }
}
abstract class Abstraction {
protected Implementor implementor;
public Abstraction(Implementor impl) { this.implementor = impl; }
abstract void operation();
}
class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor impl) { super(impl); }
public void operation() { implementor.operationImpl(); }
} Java (Extended)
interface Renderer { void renderShape(String shape); }
class VectorRenderer implements Renderer {
public void renderShape(String shape) { System.out.println("Vector: " + shape); }
}
class RasterRenderer implements Renderer {
public void renderShape(String shape) { System.out.println("Raster: " + shape); }
}
abstract class Shape {
protected Renderer renderer;
public Shape(Renderer r) { this.renderer = r; }
abstract void draw();
}
class Circle extends Shape {
public Circle(Renderer r) { super(r); }
public void draw() { renderer.renderShape("Circle"); }
} Basics
Composes objects into tree structures to represent part-whole hierarchies.
Description
The Composite pattern is a structural pattern that treats individual objects and compositions uniformly. It’s perfect for hierarchical systems like file directories or UI components, enabling recursive operations across leaves and composites.
Structure
Key Components
| Component | Description |
|---|---|
| Component | Interface for all objects. |
| Leaf | Individual object. |
| Composite | Container for components. |
Examples
Java (Basic)
interface Component { void operation(); }
class Leaf implements Component {
public void operation() { System.out.println("Leaf operation"); }
}
class Composite implements Component {
private List<Component> children = new ArrayList<>();
public void add(Component c) { children.add(c); }
public void operation() { for (Component c : children) c.operation(); }
} Java (File System)
interface FileSystemComponent {
void display();
}
class File implements FileSystemComponent {
private String name;
public File(String name) { this.name = name; }
public void display() { System.out.println("File: " + name); }
}
class Directory implements FileSystemComponent {
private String name;
private List<FileSystemComponent> components = new ArrayList<>();
public Directory(String name) { this.name = name; }
public void add(FileSystemComponent c) { components.add(c); }
public void display() {
System.out.println("Directory: " + name);
for (FileSystemComponent c : components) c.display();
}
} Basics
Attaches additional responsibilities to an object dynamically.
Description
The Decorator pattern is a structural pattern that extends object functionality without subclassing, using composition. It’s widely used in I/O streams or UI embellishments, offering a flexible alternative to inheritance for adding features.
Structure
Key Components
| Component | Description |
|---|---|
| Component | Base interface. |
| Concrete Component | Core object. |
| Decorator | Wraps and extends component. |
Examples
Java (Basic)
interface Component { void operation(); }
class ConcreteComponent implements Component {
public void operation() { System.out.println("Base operation"); }
}
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component c) { this.component = c; }
public void operation() { component.operation(); }
}
class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component c) { super(c); }
public void operation() {
super.operation();
System.out.println("Added behavior");
}
} Java (Coffee Shop)
interface Coffee { String getDescription(); double cost(); }
class SimpleCoffee implements Coffee {
public String getDescription() { return "Simple Coffee"; }
public double cost() { return 2.0; }
}
abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee c) { this.coffee = c; }
public String getDescription() { return coffee.getDescription(); }
public double cost() { return coffee.cost(); }
}
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee c) { super(c); }
public String getDescription() { return coffee.getDescription() + ", Milk"; }
public double cost() { return coffee.cost() + 0.5; }
} Basics
Provides a simplified interface to a complex subsystem.
Description
The Facade pattern is a structural pattern that hides subsystem complexity behind a single, easy-to-use interface. It’s common in APIs or libraries, reducing client coupling to internal details while still allowing access to advanced functionality if needed.
Structure
Key Components
| Component | Description |
|---|---|
| Facade | Simplified interface. |
| Subsystem Classes | Complex internal components. |
Examples
Java (Basic)
class SubsystemA { void operationA() { System.out.println("A"); } }
class SubsystemB { void operationB() { System.out.println("B"); } }
class Facade {
private SubsystemA a = new SubsystemA();
private SubsystemB b = new SubsystemB();
public void operation() { a.operationA(); b.operationB(); }
} Java (Home Theater)
class DVDPlayer { void play() { System.out.println("DVD playing"); } }
class Projector { void on() { System.out.println("Projector on"); } }
class SoundSystem { void setVolume(int level) { System.out.println("Volume: " + level); } }
class HomeTheaterFacade {
private DVDPlayer dvd = new DVDPlayer();
private Projector projector = new Projector();
private SoundSystem sound = new SoundSystem();
public void watchMovie() {
projector.on();
sound.setVolume(5);
dvd.play();
}
} Basics
Uses sharing to support large numbers of fine-grained objects efficiently.
Description
The Flyweight pattern is a structural pattern that minimizes memory usage by sharing common data across objects. It’s ideal for scenarios with many similar objects (e.g., characters in a text editor), splitting intrinsic (shared) and extrinsic (context-specific) state.
Structure
Key Components
| Component | Description |
|---|---|
| Flyweight | Interface for shared objects. |
| Flyweight Factory | Manages shared instances. |
| Client | Uses flyweights with extrinsic state. |
Examples
Java (Basic)
interface Flyweight { void operation(String extrinsic); }
class ConcreteFlyweight implements Flyweight {
private String intrinsicState;
public ConcreteFlyweight(String intrinsic) { this.intrinsicState = intrinsic; }
public void operation(String extrinsic) { System.out.println(intrinsicState + ": " + extrinsic); }
}
class FlyweightFactory {
private Map<String, Flyweight> flyweights = new HashMap<>();
public Flyweight getFlyweight(String key) {
return flyweights.computeIfAbsent(key, k -> new ConcreteFlyweight(k));
}
} Java (Text Editor)
interface CharacterFlyweight { void display(int position); }
class ConcreteCharacter implements CharacterFlyweight {
private char symbol;
public ConcreteCharacter(char symbol) { this.symbol = symbol; }
public void display(int position) { System.out.println(symbol + " at " + position); }
}
class CharacterFactory {
private Map<Character, CharacterFlyweight> characters = new HashMap<>();
public CharacterFlyweight getCharacter(char c) {
return characters.computeIfAbsent(c, k -> new ConcreteCharacter(k));
}
} Basics
Provides a surrogate or placeholder for another object to control access to it.
Description
The Proxy pattern is a structural pattern that acts as an intermediary, adding functionality like lazy loading, access control, or logging. It’s used in remote proxies (e.g., web services), virtual proxies (e.g., image loading), or protection proxies.
Structure
Key Components
| Component | Description |
|---|---|
| Subject | Interface for real and proxy objects. |
| Real Subject | Actual object being proxied. |
| Proxy | Controls access to real subject. |
Examples
Java (Virtual Proxy)
interface Image { void display(); }
class RealImage implements Image {
private String file;
public RealImage(String file) { this.file = file; load(); }
private void load() { System.out.println("Loading " + file); }
public void display() { System.out.println("Displaying " + file); }
}
class ProxyImage implements Image {
private RealImage realImage;
private String file;
public ProxyImage(String file) { this.file = file; }
public void display() {
if (realImage == null) realImage = new RealImage(file);
realImage.display();
}
} Java (Protection Proxy)
interface Resource { void access(); }
class RealResource implements Resource {
public void access() { System.out.println("Resource accessed"); }
}
class ProxyResource implements Resource {
private RealResource resource;
private String user;
public ProxyResource(String user) { this.user = user; }
public void access() {
if (user.equals("admin")) {
if (resource == null) resource = new RealResource();
resource.access();
} else {
System.out.println("Access denied");
}
}
} Basics
Defines a one-to-many dependency so that when one object changes state, all dependents are notified.
Description
The Observer pattern is a behavioral pattern for event-driven systems, where subjects notify observers of state changes. It’s prevalent in GUI frameworks, pub-sub models, and reactive programming, decoupling publishers from subscribers.
Structure
Key Components
| Component | Description |
|---|---|
| Subject | Tracks state and observers. |
| Observer | Receives updates. |
| Concrete Observer | Implements update logic. |
Examples
Java (Basic)
import java.util.ArrayList;
import java.util.List;
interface Observer { void update(String message); }
class Subject {
private List<Observer> observers = new ArrayList<>();
private String state;
public void attach(Observer o) { observers.add(o); }
public void setState(String state) {
this.state = state;
notifyObservers();
}
private void notifyObservers() { for (Observer o : observers) o.update(state); }
}
class ConcreteObserver implements Observer {
public void update(String message) { System.out.println("Update: " + message); }
} Java (Using java.util)
import java.util.Observable;
import java.util.Observer;
class NewsAgency extends Observable {
private String news;
public void setNews(String news) {
this.news = news;
setChanged();
notifyObservers(news);
}
}
class NewsChannel implements Observer {
public void update(Observable o, Object arg) {
System.out.println("News: " + arg);
}
}
class Demo {
public static void main(String[] args) {
NewsAgency agency = new NewsAgency();
NewsChannel channel = new NewsChannel();
agency.addObserver(channel);
agency.setNews("Breaking News!");
}
} Basics
Defines a family of algorithms, encapsulating each one, and makes them interchangeable.
Description
The Strategy pattern is a behavioral pattern that enables runtime algorithm selection, promoting flexibility and reuse. It’s used in sorting, payment processing, or any scenario where behavior varies, avoiding conditional logic in favor of polymorphism.
Structure
Key Components
| Component | Description |
|---|---|
| Strategy | Algorithm interface. |
| Concrete Strategy | Specific algorithm implementation. |
| Context | Uses the strategy. |
Examples
Java (Basic)
interface Strategy { int execute(int a, int b); }
class AddStrategy implements Strategy {
public int execute(int a, int b) { return a + b; }
}
class SubtractStrategy implements Strategy {
public int execute(int a, int b) { return a - b; }
}
class Context {
private Strategy strategy;
public void setStrategy(Strategy s) { this.strategy = s; }
public int executeStrategy(int a, int b) { return strategy.execute(a, b); }
} Java (Payment)
interface PaymentStrategy { void pay(double amount); }
class CreditCardStrategy implements PaymentStrategy {
private String cardNumber;
public CreditCardStrategy(String cardNumber) { this.cardNumber = cardNumber; }
public void pay(double amount) { System.out.println(amount + " paid with card " + cardNumber); }
}
class PayPalStrategy implements PaymentStrategy {
private String email;
public PayPalStrategy(String email) { this.email = email; }
public void pay(double amount) { System.out.println(amount + " paid via PayPal " + email); }
}
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy ps) { this.paymentStrategy = ps; }
public void checkout(double amount) { paymentStrategy.pay(amount); }
} Basics
Encapsulates a request as an object, allowing parameterization and queuing.
Description
The Command pattern is a behavioral pattern that turns requests into standalone objects, enabling undo/redo, logging, or delayed execution. It’s common in UI actions, transaction systems, or macros, decoupling invokers from receivers.
Structure
Key Components
| Component | Description |
|---|---|
| Command | Interface for actions. |
| Concrete Command | Binds receiver to action. |
| Invoker | Triggers command. |
| Receiver | Performs the action. |
Examples
Java (Basic)
interface Command { void execute(); }
class Receiver { public void action() { System.out.println("Action"); } }
class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver r) { this.receiver = r; }
public void execute() { receiver.action(); }
}
class Invoker {
private Command command;
public void setCommand(Command c) { this.command = c; }
public void executeCommand() { command.execute(); }
} Java (Undoable)
interface Command { void execute(); void undo(); }
class Light {
public void on() { System.out.println("Light on"); }
public void off() { System.out.println("Light off"); }
}
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) { this.light = light; }
public void execute() { light.on(); }
public void undo() { light.off(); }
}
class RemoteControl {
private Command command;
public void setCommand(Command c) { this.command = c; }
public void pressButton() { command.execute(); }
public void pressUndo() { command.undo(); }
} Basics
Defines the skeleton of an algorithm, letting subclasses override specific steps.
Description
The Template Method pattern is a behavioral pattern that outlines an algorithm’s structure while allowing customization of steps. It’s used in frameworks or base classes where common behavior is fixed but details vary, like game loops or data processing.
Structure
Key Components
| Component | Description |
|---|---|
| Abstract Class | Defines template method and steps. |
| Concrete Class | Implements variable steps. |
Examples
Java (Basic)
abstract class AbstractClass {
public void templateMethod() {
step1();
step2();
}
abstract void step1();
abstract void step2();
}
class ConcreteClass extends AbstractClass {
void step1() { System.out.println("Step 1"); }
void step2() { System.out.println("Step 2"); }
} Java (Game Loop)
abstract class Game {
public final void play() {
initialize();
startPlay();
endPlay();
}
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
}
class Chess extends Game {
void initialize() { System.out.println("Chess initialized"); }
void startPlay() { System.out.println("Chess started"); }
void endPlay() { System.out.println("Chess ended"); }
} Basics
Defines an object that encapsulates how a set of objects interact.
Description
The Mediator pattern is a behavioral pattern that centralizes communication between objects, reducing direct dependencies. It’s used in chat systems or air traffic control, where objects need coordinated interaction without tight coupling.
Structure
Key Components
| Component | Description |
|---|---|
| Mediator | Interface for communication. |
| Concrete Mediator | Coordinates objects. |
| Colleague | Interacts via mediator. |
Examples
Java (Basic)
interface Mediator { void send(String msg, Colleague sender); }
class ConcreteMediator implements Mediator {
private List<Colleague> colleagues = new ArrayList<>();
public void add(Colleague c) { colleagues.add(c); }
public void send(String msg, Colleague sender) {
for (Colleague c : colleagues) if (c != sender) c.receive(msg);
}
}
abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator m) { this.mediator = m; }
abstract void receive(String msg);
}
class ConcreteColleague extends Colleague {
public ConcreteColleague(Mediator m) { super(m); }
public void send(String msg) { mediator.send(msg, this); }
public void receive(String msg) { System.out.println("Received: " + msg); }
} Java (Chat Room)
interface ChatMediator { void sendMessage(String msg, User sender); }
class ChatRoom implements ChatMediator {
private List<User> users = new ArrayList<>();
public void addUser(User u) { users.add(u); }
public void sendMessage(String msg, User sender) {
for (User u : users) if (u != sender) u.receive(msg);
}
}
class User {
private ChatMediator mediator;
private String name;
public User(ChatMediator m, String name) { this.mediator = m; this.name = name; }
public void send(String msg) { mediator.sendMessage(msg, this); }
public void receive(String msg) { System.out.println(name + " received: " + msg); }
} Basics
Passes a request along a chain of handlers until one processes it.
Description
The Chain of Responsibility pattern is a behavioral pattern that decouples senders from receivers by allowing multiple objects to handle a request. It’s used in logging frameworks or event handling, where handlers process or pass requests dynamically.
Structure
Key Components
| Component | Description |
|---|---|
| Handler | Interface for handling requests. |
| Concrete Handler | Processes or forwards requests. |
| Client | Initiates the chain. |
Examples
Java (Basic)
abstract class Handler {
protected Handler next;
public void setNext(Handler next) { this.next = next; }
abstract void handleRequest(String request);
}
class ConcreteHandler1 extends Handler {
public void handleRequest(String request) {
if (request.equals("A")) System.out.println("Handler 1");
else if (next != null) next.handleRequest(request);
}
}
class ConcreteHandler2 extends Handler {
public void handleRequest(String request) {
if (request.equals("B")) System.out.println("Handler 2");
else if (next != null) next.handleRequest(request);
}
} Java (Logger)
abstract class Logger {
protected Logger next;
protected int level;
public void setNext(Logger next) { this.next = next; }
public void log(int level, String msg) {
if (this.level <= level) write(msg);
if (next != null) next.log(level, msg);
}
abstract void write(String msg);
}
class ConsoleLogger extends Logger {
public ConsoleLogger(int level) { this.level = level; }
void write(String msg) { System.out.println("Console: " + msg); }
}
class FileLogger extends Logger {
public FileLogger(int level) { this.level = level; }
void write(String msg) { System.out.println("File: " + msg); }
} Basics
Allows an object to alter its behavior when its internal state changes.
Description
The State pattern is a behavioral pattern that encapsulates state-specific behavior, making an object appear to change class. It’s used in state machines, game characters, or workflows, improving maintainability over conditionals.
Structure
Key Components
| Component | Description |
|---|---|
| Context | Holds current state. |
| State | Interface for state behavior. |
| Concrete State | Implements state-specific actions. |
Examples
Java (Basic)
interface State { void handle(Context context); }
class ConcreteStateA implements State {
public void handle(Context context) {
System.out.println("State A");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB implements State {
public void handle(Context context) {
System.out.println("State B");
context.setState(new ConcreteStateA());
}
}
class Context {
private State state;
public Context() { state = new ConcreteStateA(); }
public void setState(State s) { this.state = s; }
public void request() { state.handle(this); }
} Java (Traffic Light)
interface TrafficLightState { void next(TrafficLight light); }
class RedState implements TrafficLightState {
public void next(TrafficLight light) {
System.out.println("Red");
light.setState(new GreenState());
}
}
class GreenState implements TrafficLightState {
public void next(TrafficLight light) {
System.out.println("Green");
light.setState(new YellowState());
}
}
class YellowState implements TrafficLightState {
public void next(TrafficLight light) {
System.out.println("Yellow");
light.setState(new RedState());
}
}
class TrafficLight {
private TrafficLightState state;
public TrafficLight() { state = new RedState(); }
public void setState(TrafficLightState s) { this.state = s; }
public void change() { state.next(this); }
} Basics
Represents an operation to be performed on elements of an object structure without modifying their classes.
Description
The Visitor pattern is a behavioral pattern that externalizes operations on a structure, allowing new functionality without altering the structure’s classes. It’s used in compilers or tree traversals, separating algorithms from data.
Structure
Key Components
| Component | Description |
|---|---|
| Visitor | Interface for operations. |
| Concrete Visitor | Implements operations. |
| Element | Accepts visitors. |
Examples
Java (Basic)
interface Visitor { void visit(ElementA a); void visit(ElementB b); }
interface Element { void accept(Visitor v); }
class ElementA implements Element {
public void accept(Visitor v) { v.visit(this); }
public void operationA() { System.out.println("A"); }
}
class ElementB implements Element {
public void accept(Visitor v) { v.visit(this); }
public void operationB() { System.out.println("B"); }
}
class ConcreteVisitor implements Visitor {
public void visit(ElementA a) { a.operationA(); }
public void visit(ElementB b) { b.operationB(); }
} Java (Shopping Cart)
interface Visitor { void visit(Book b); void visit(Electronic e); }
interface Item { void accept(Visitor v); double getPrice(); }
class Book implements Item {
private double price;
public Book(double price) { this.price = price; }
public void accept(Visitor v) { v.visit(this); }
public double getPrice() { return price; }
}
class Electronic implements Item {
private double price;
public Electronic(double price) { this.price = price; }
public void accept(Visitor v) { v.visit(this); }
public double getPrice() { return price; }
}
class PriceVisitor implements Visitor {
private double total = 0;
public void visit(Book b) { total += b.getPrice(); }
public void visit(Electronic e) { total += e.getPrice() * 1.1; } // Tax
public double getTotal() { return total; }
}