Reference

Pattern Relationships

Confused-with pairs, compose-together groups, and modern alternatives.

01
Commonly Confused

Confused-With Pairs

These pattern pairs share surface-level similarities but solve fundamentally different problems. Interviewers love asking “What’s the difference between X and Y?” — and a vague answer signals shallow understanding.

Strategy vs. State
Both change an object’s behaviour at runtime. The difference is who triggers the change.
StrategyState
Intent Swap an algorithm from the outside Object transitions its own behaviour from the inside
Who decides? The client picks the strategy and injects it The current state decides the next state
Awareness Strategies don’t know about each other States know about and transition to other states
Classic example Payment method (CreditCard, PayPal, Crypto) Order lifecycle (Pending → Paid → Shipped → Delivered)
Key test Can the client swap the behaviour arbitrarily at any time? Does the object follow a defined state machine with valid transitions?
Decorator vs. Proxy
Both wrap another object with the same interface. The difference is purpose.
DecoratorProxy
Intent Add new behaviour / responsibilities Control access to the real object
Lifecycle Client creates the real object and wraps it Proxy often creates or manages the real object itself
Stacking Multiple decorators stack: new A(new B(new C(real))) Typically a single proxy wrapping the real subject
Classic example BufferedReader(new FileReader(f)) — adds buffering Spring AOP @Transactional proxy — controls when the real method runs
Key test Does it add features the real object doesn’t have? Does it control when/whether the real object is accessed?
Factory Method vs. Abstract Factory
Both decouple object creation. The difference is scope: one product vs. a family.
Factory MethodAbstract Factory
Creates One product type A family of related products
Mechanism Abstract method overridden in a subclass Interface with multiple factory methods
Extensibility One new subclass per new product One new factory implementation per new family
Classic example Collection.iterator() — each collection returns its own iterator UI toolkit: WindowsFactory creates WindowsButton + WindowsCheckbox together
Key test Does the subclass decide which single product to create? Do multiple products need to be used together consistently?
Composite vs. Decorator
Both use recursive composition with a shared interface. The difference is structure vs. behaviour.
CompositeDecorator
Intent Represent tree structures uniformly (leaf = branch) Add behaviour dynamically via wrapping
Children Composite holds multiple children Decorator wraps exactly one object
Delegation Aggregates results from children (e.g. sum all sizes) Delegates to the wrapped object, adding before/after behaviour
Classic example File system: Directory.getSize() sums children Coffee: new Milk(new Sugar(new Espresso()))
Key test Do you need to treat a group the same as an individual? Do you need to add optional features without subclassing?
Command vs. Strategy
Both encapsulate behaviour as an object. The difference is history and lifecycle.
CommandStrategy
Intent Encapsulate a request as an object (with undo, queue, log) Encapsulate an algorithm that can be swapped
Lifecycle Commands are stored, queued, undone, replayed Strategy is selected once and used — no history
Undo Core feature: execute() + undo() Not applicable
Classic example Text editor: push BoldCommand to undo stack Sort with Comparator: swap sort algorithm at runtime
Key test Do you need to store, queue, or undo operations? Do you need to swap one algorithm for another at runtime?
02
Composition

Compose-Together Groups

Patterns rarely work alone in real systems. These groups are natural companions — they solve adjacent problems and reinforce each other. Learning the combinations is what separates textbook knowledge from production design skill.

Composite + Iterator + Visitor
  • Composite defines the tree structure (files & directories)
  • Iterator traverses the tree without exposing its internals
  • Visitor adds operations (size calculation, search, export) without modifying node classes
  • Real-world: AST processing in compilers, DOM traversal, file system utilities
Abstract Factory + Builder
  • Abstract Factory decides which builder to use (e.g. WindowsUIBuilder vs. MacUIBuilder)
  • Builder constructs the complex product step-by-step
  • Real-world: Cross-platform UI toolkits, configuration systems that vary by environment
Observer + Mediator
  • Mediator centralises communication between components
  • Observer is used internally by the Mediator to notify colleagues of changes
  • Real-world: Chat rooms (Mediator routes messages, Observer notifies online users), event buses
Command + Memento
  • Command encapsulates what action was taken (for undo/redo)
  • Memento captures what state looked like before (for restoration)
  • Together: Command says “undo this bold”; Memento restores the exact text state before the bold was applied
  • Real-world: Text editors, graphics editors, database transaction rollback
Factory Method + Template Method
  • Template Method defines the algorithm skeleton
  • Factory Method is one step in that algorithm — the step that creates the product
  • Real-world: Framework extension points (Spring’s AbstractController, JUnit test lifecycle)
Strategy + Decorator
  • Strategy swaps the core algorithm
  • Decorator adds cross-cutting concerns around it (logging, caching, retry)
  • Together: new RetryDecorator(new LoggingDecorator(new PayPalStrategy()))
  • Real-world: HTTP clients, payment processors, notification pipelines
Interview tip: When asked “Design a [complex system]”, identify which pattern handles each concern separately, then explain how they compose. This shows architectural thinking, not just pattern memorization.
03
Modern Alternatives

Modern Alternatives

The GoF patterns were published in 1994. Modern languages (Java 8+, Kotlin, Python) and frameworks (Spring, CDI) provide features that replace or simplify several classical patterns. Knowing the modern equivalent shows you’re not blindly applying textbook solutions.

Classical Pattern Modern Alternative Why the Alternative is Preferred
Singleton Dependency Injection (@Singleton scope) DI container manages the single instance; class itself has no static state, remains testable and mockable
Template Method Strategy with lambdas / functional interfaces Avoids rigid inheritance; varying steps passed as Function<T,R> or method references
Command Runnable / Callable / lambdas For simple fire-and-forget commands, a lambda is lighter than a full Command class. Reserve the pattern for undo/history.
Strategy Lambdas / Comparator.comparing() When the strategy is a single method, pass a lambda instead of creating a class: list.sort(Comparator.comparing(Order::getDate))
Observer Reactive Streams / Flow API / Event Bus Built-in backpressure, error handling, and composition. java.util.Observable deprecated since Java 9.
Iterator Stream API / Iterable.forEach() Declarative pipeline with filter(), map(), reduce() rather than imperative hasNext()/next()
Factory Method Supplier<T> / method references When the factory is a single no-arg constructor, Supplier<Notification> factory = SmsNotification::new replaces a subclass hierarchy
When to still use the classical pattern:
  • Command → when you need undo, history, queuing, or macro recording — a lambda can’t undo itself
  • Strategy → when the strategy has multiple methods or internal state — a lambda covers only one method
  • Observer → when you need custom subscription logic, filtering, or priority ordering
  • Singleton → in libraries without a DI container, or for JVM-level resources (Runtime, SecurityManager)
Modern Java — Strategy as a lambda
// Classical: create a DiscountStrategy class // Modern: pass a Function directly Function<Order, BigDecimal> tenPercentOff = order -> order.getTotal().multiply(new BigDecimal("0.90")); Function<Order, BigDecimal> freeShipping = order -> order.getTotal().subtract(order.getShippingCost()); // Swap strategy at runtime โ€” no class needed BigDecimal finalPrice = discountStrategy.apply(order);
Modern Java — Factory Method as Supplier
// Classical: abstract class with createNotification() overridden in subclasses // Modern: pass the constructor as a Supplier Map<String, Supplier<Notification>> factories = Map.of( "email", EmailNotification::new, "sms", SmsNotification::new, "push", PushNotification::new ); Notification n = factories.get("sms").get(); n.send("Your order shipped!");
04
Visual Map

Pattern Relationship Map

This map shows all major relationships between the 23 GoF patterns. Solid lines = compose together. Dashed lines = commonly confused. Blue labels = the distinguishing factor.

GoF Pattern Relationships โ€” Confused, Composed, and Alternatives
CREATIONAL Singleton Factory Method Abstract Factory Builder Prototype confused compose STRUCTURAL Adapter Bridge Composite Decorator Facade Flyweight Proxy confused: adds features vs. controls access confused BEHAVIORAL Observer Strategy Command State Template Method Mediator confused: outside swap vs. inside transition confused alternative: prefer Strategy (composition) over Template Method (inheritance) compose: Mediator uses Observer to notify colleagues Composite + Iterator + Visitor (tree traversal trio) = commonly confused = compose together = modern alternative ■ Creational ■ Structural ■ Behavioral
05
Quick Reference

Decision Cheat Sheet

When you’re staring at a confused pair, ask these one-liner questions to pick the right pattern:

If you’re wondering… Ask this question Answer → Pattern
Strategy or State? Does the object change its own behaviour based on internal conditions? Yes → State  |  No → Strategy
Decorator or Proxy? Are you adding new features or controlling access to existing ones? Adding → Decorator  |  Controlling → Proxy
Factory Method or Abstract Factory? Do you need one product or a family that must match? One → FM  |  Family → AF
Command or Strategy? Do you need to store, queue, or undo the operation? Yes → Command  |  No → Strategy
Composite or Decorator? Are you building a tree or wrapping behaviour? Tree → Composite  |  Wrapper → Decorator
Adapter or Bridge? Is it designed upfront or retrofitted? Upfront → Bridge  |  Retrofit → Adapter
Facade or Mediator? Is communication one-directional (client → subsystem) or bidirectional? One-way → Facade  |  Two-way → Mediator
Interview tip: When an interviewer asks “Isn’t that just a Strategy?” or “How is this different from Decorator?”, they want you to state the one distinguishing question from the table above. A crisp one-sentence answer beats a rambling explanation.