Gang of Four · Design Patterns Reference

Design Patterns

Elements of Reusable Object-Oriented Software — a structured reference to all 23 patterns across creational, structural, and behavioral categories.

Creational

Creational Patterns

Creational patterns abstract the instantiation process. They help make a system independent of how its objects are created, composed, and represented. Rather than hard-coding the specific classes that get instantiated, these patterns encapsulate knowledge about which concrete classes the system uses and hide how instances are created and put together.

As systems evolve to depend more on object composition than class inheritance, these patterns become increasingly important. They give you flexibility in what gets created, who creates it, how it's created, and when.

Two recurring themes run through all five: they encapsulate knowledge about which concrete classes the system uses, and they hide how instances are created and assembled.

Key Themes

  • Hide concrete classes from clients
  • Defer instantiation to subclasses or objects
  • Program to an interface, not an implementation
  • Support "open/closed" object creation
  • Enable configuration at compile- or run-time
01 · Object Creational
Abstract Factory
Also known as: Kit
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
+

When a system must be independent of how its products are created, or when it must work with one of several families of products, Abstract Factory defines an interface for creating each kind of product. Concrete factories implement this interface for specific product families. Clients create objects solely through the factory interface and never know the concrete classes they're using.

Classic example: a UI toolkit supporting multiple look-and-feel standards (Motif, Windows, macOS). A WidgetFactory interface declares createScrollBar(), createButton(), etc. MotifWidgetFactory and WindowsWidgetFactory implement these to return the right widget style. Swapping the factory switches the entire look-and-feel at once.

AbstractFactory
Declares creation operations for each distinct product type.
ConcreteFactory
Implements creation of a specific product family (e.g., MotifFactory).
AbstractProduct
Declares interface for a type of product object (e.g., Button, ScrollBar).
ConcreteProduct
Defines the product created by the corresponding factory; implements AbstractProduct.
Client
Uses only AbstractFactory and AbstractProduct interfaces.
✓ Isolates concrete classes — product class names never appear in client code.
✓ Makes exchanging product families trivial — change one factory object to switch the whole family.
✓ Enforces consistency among products — only one family used at a time.
✗ Supporting new kinds of products is hard — the AbstractFactory interface is fixed, so extending it changes all subclasses.
  • Cross-platform GUI toolkits (Swing Look & Feel, Qt styles)
  • Database abstraction layers that must support multiple DB engines (MySQL, PostgreSQL, SQLite)
  • Game engines that swap rendering backends (OpenGL, DirectX, Vulkan) without touching game logic
  • Cloud provider SDKs abstracting compute, storage, and networking across AWS, Azure, GCP
  • Theme systems in design frameworks (dark/light mode, brand families)
02 · Object Creational
Builder
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
+

When object construction is complex and requires multiple steps, and when you need the same construction process to yield different results, Builder separates the construction algorithm (the Director) from the parts being assembled (the Builder). The client delegates construction to the Director, which uses the Builder interface step-by-step.

Classic example: an RTF document reader that must convert RTF to different formats (plain ASCII, TeX, an editable widget). The RTFReader is the Director — it parses the document. ASCIIConverter, TeXConverter, and TextWidgetConverter are Builders that assemble different representations as the reader feeds them tokens. Adding a new output format only requires a new Builder — the reader never changes.

Builder
Abstract interface for creating parts of a Product object.
ConcreteBuilder
Constructs and tracks parts; provides a method to retrieve the finished product.
Director
Constructs an object using the Builder interface, controlling build order.
Product
The complex object under construction; its internal structure is defined by ConcreteBuilder.

Both create complex objects. The key difference: Builder constructs step-by-step under director control and returns the product as the final step. Abstract Factory returns a product immediately and focuses on families of products. Builder gives you finer control over the construction process and the product's internal structure.

✓ Vary a product's internal representation — just define a new builder.
✓ Isolates construction code from representation — the director and builder are cleanly separated.
✓ Fine-grained control over construction — steps can include validation, transformation, etc.
✗ Requires a separate ConcreteBuilder for each product type, even if differences are small.
  • SQL query builders in ORMs (Hibernate Criteria API, SQLAlchemy, LINQ)
  • HTTP request builders (Java's HttpClient.newBuilder(), Python's requests.Request)
  • Document generation (HTML, PDF, or Word from one content model)
  • Configuration objects with dozens of optional settings (Java's StringBuilder, Kotlin's DSL builders)
  • Game level/map creation pipelines assembling terrain, objects, and NPCs
  • Pizza-ordering systems: same steps (set size, crust, toppings) produce different pizzas
03 · Class Creational
Factory Method
Also known as: Virtual Constructor
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
+

A framework must instantiate classes specific to an application, but it only knows about abstract classes. Factory Method solves this by defining a virtual creation operation — a factory method — that subclasses override to return an appropriate instance.

Classic example: a document-editing framework with abstract Application and Document classes. Application knows when to create a document but not what kind. The abstract createDocument() factory method lets DrawingApplication and SpreadsheetApplication each return their own document type. The framework code stays untouched.

Product
Defines the interface of objects the factory method creates.
ConcreteProduct
Implements the Product interface.
Creator
Declares the factory method; may call it to create Products internally.
ConcreteCreator
Overrides the factory method to return an instance of ConcreteProduct.
✓ Eliminates binding to application-specific classes — code only depends on the Product interface.
✓ Provides a hook for subclasses to provide extended versions of an object.
✓ Connects parallel class hierarchies cleanly.
✗ May force clients to subclass Creator just to instantiate a particular ConcreteProduct.
  • Java's Calendar.getInstance() returns the right subtype for the locale
  • Spring Framework's BeanFactory — creates beans via factory methods
  • Logger factories (log4j's LogManager.getLogger())
  • Plugin/extension loading systems — a host application lets plug-ins define what objects to create
  • Test frameworks creating mock objects based on the test class
  • React hooks as a form of factory method for creating stateful logic
04 · Object Creational
Prototype
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
+

Sometimes the class to instantiate is specified only at runtime, or you want to avoid a parallel hierarchy of factory classes. Prototype lets you clone an existing object (the prototype) instead. Each class implements a clone() operation. Clients ask a prototype to clone itself rather than calling a constructor.

Classic example: a music-score editor where each tool in the palette is a GraphicTool initialized with a different prototype (a quarter note, half note, etc.). Clicking a tool clones its prototype and adds it to the score. One GraphicTool class handles all music objects — no proliferation of subclasses needed.

Prototype
Declares an interface for cloning itself.
ConcretePrototype
Implements the Clone operation; typically a deep copy.
Client
Creates new objects by asking a prototype to clone itself.

Shallow vs. deep copy: A shallow copy shares references with the original; a deep copy recursively clones all referenced objects. Complex structures usually require deep copies to keep the clone independent.

Prototype manager: When prototypes are dynamic, a registry (associative store) lets you register/look up prototypes by key without hardcoding anything.

✓ Add/remove products at runtime — just register or unregister prototype instances.
✓ Reduces subclassing — no need for a Creator hierarchy parallel to the product hierarchy.
✓ Configure an application dynamically with classes loaded at runtime.
✗ Every Prototype subclass must implement Clone, which can be tricky with circular references or objects that don't support copying.
  • JavaScript's object prototype chain — new objects inherit from prototypes
  • Copy-paste in graphical editors (clone the selected shapes)
  • Game: spawning enemy waves by cloning a template enemy with different configurations
  • Virtual machine snapshots — a VM image is a prototype cloned into new instances
  • Document templates — a template document is cloned to start a new document
  • Python's copy.deepcopy() is a language-level prototype mechanism
05 · Object Creational
Singleton
Ensure a class only has one instance, and provide a global point of access to it.
+

Some classes should have exactly one instance — a printer spooler, a filesystem, a configuration store, a window manager. Ordinary global variables don't prevent multiple instantiations. Singleton makes the class itself responsible for its sole instance: the constructor is private, and a static method returns the unique instance (creating it lazily on first access).

Singleton
Defines an Instance() class operation. Maintains a pointer/reference to the sole instance. Constructor is protected or private.
✓ Controlled access — the class encapsulates and controls its sole instance.
✓ Reduced namespace pollution vs. global variables.
✓ Allows refinement via subclassing and can support a controlled number of instances.
✗ Introduces global state, making code harder to test in isolation.
✗ Thread safety requires careful implementation (double-checked locking, initialization-on-demand).
✗ Violates Single Responsibility Principle — the class manages both its core logic and its own lifecycle.
  • Application configuration objects read once at startup
  • Logger instances (e.g., Python's logging.getLogger(name) is registry-based singleton-like)
  • Connection pools — a single pool manages all database connections
  • Cache managers — one cache object shared across the application
  • Hardware device drivers — only one instance should talk to the physical device
  • Thread pools or task executors in concurrent applications
Structural

Structural Patterns

Structural patterns are concerned with how classes and objects are composed to form larger structures. Class-level structural patterns use inheritance to compose interfaces or implementations. Object-level structural patterns describe ways to assemble objects at runtime — gaining the flexibility to change compositions dynamically.

The key insight is that structure and composition are distinct from behavior. These patterns help you manage the relationship between parts and wholes, control access to objects, adapt mismatched interfaces, and share state efficiently.

A recurring challenge they address: as systems grow, class hierarchies balloon. These patterns offer flexible, composition-based alternatives that keep hierarchies manageable.

Key Themes

  • Compose objects to form larger structures
  • Favor object composition over class inheritance
  • Provide levels of indirection to objects
  • Decouple abstractions from implementations
  • Adapt mismatched interfaces without modifying code
06 · Class/Object Structural
Adapter
Also known as: Wrapper
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
+

You have an existing class with the right behavior but the wrong interface. Rather than modify the class (you may not own the source) or duplicate its logic, an Adapter wraps it to expose the expected interface. There are two forms:

Class Adapter uses multiple inheritance — publicly inherits the target interface, privately inherits the adaptee's implementation. Works only for adapting a single class.

Object Adapter wraps an adaptee instance via composition — more flexible, works with the adaptee and all its subclasses.

Target
The domain-specific interface the client expects.
Adaptee
An existing interface that needs adapting.
Adapter
Adapts Adaptee's interface to the Target interface.
Client
Collaborates with objects conforming to the Target interface.
✓ Reuse existing classes without modifying them — adapter bridges incompatible interfaces.
✓ Object adapter can adapt a class and all its subclasses, and can add functionality to all at once.
✗ Class adapter can't adapt a class and all its subclasses at once.
✗ Object adapter makes it harder to override Adaptee behavior.
  • Java's Arrays.asList() adapts a plain array to the List interface
  • JDBC drivers adapt vendor-specific database APIs to the standard Java SQL interface
  • Power adapters converting electrical plugs (physical-world analogy)
  • REST API wrappers adapting a third-party service's HTTP responses to your domain model
  • Legacy system integration — adapting an old SOAP service to a new REST interface
  • Input readers in compilers adapting file/string/stream sources to a uniform token stream
07 · Object Structural
Bridge
Also known as: Handle/Body
Decouple an abstraction from its implementation so that the two can vary independently.
+

When both an abstraction and its implementation must be extensible by subclassing, inheritance alone leads to a cartesian-product explosion of subclasses. Bridge solves this by putting the abstraction and the implementation in separate class hierarchies, connected by a reference (the "bridge").

Classic example: a portable Window abstraction that must work on X11 and Presentation Manager, and must support multiple window kinds (application window, icon, dialog). Without Bridge, you'd need XApplicationWindow, PMApplicationWindow, XIconWindow, PMIconWindow, etc. With Bridge, Window and WindowImp are separate hierarchies — mix and match freely.

Abstraction
Defines the abstraction interface; maintains a reference to an Implementor.
RefinedAbstraction
Extends the Abstraction interface.
Implementor
Defines the interface for implementation classes (often more primitive operations).
ConcreteImplementor
Implements the Implementor interface for a specific platform/backend.

Both involve a level of indirection, but their intent differs. Adapter is applied retroactively to make two existing, incompatible classes work together. Bridge is designed upfront — knowing that both abstraction and implementation will evolve independently.

✓ Decouples interface and implementation — implementations can change or be swapped at runtime.
✓ Improved extensibility — both hierarchies can grow independently.
✓ Hides implementation details from clients completely.
✗ Adds complexity with a level of indirection — may be over-engineering for simple scenarios.
  • JDBC: the Connection abstraction bridges to vendor-specific JDBC driver implementations
  • Device drivers: OS kernel abstractions bridging to hardware-specific implementations
  • UI rendering: abstract shape hierarchy bridging to platform-specific drawing APIs (GDI, Core Graphics, Skia)
  • Notification systems: abstract Notifier bridging to email, SMS, push notification implementations
  • Cross-platform graphics engines separating high-level scene graph from low-level GPU API
08 · Object Structural
Composite
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
+

When a system must deal with hierarchies where individual items and groups of items must be treated the same way, Composite defines a unified interface for both. A Leaf implements it for atomic items; a Composite implements it for containers of other components. Clients use the shared interface without caring whether they're talking to a leaf or a container.

Classic example: a drawing editor with lines, circles, and text. A Picture is a group of these shapes — but it also acts like a shape (you can move, scale, or draw it). Composite objects can contain other composites, so a group can contain groups, recursively.

Component
Declares the interface for objects in the composition; implements default behavior.
Leaf
Represents leaf objects with no children; defines primitive behavior.
Composite
Defines behavior for components with children; stores child components; forwards requests to children.
Client
Manipulates objects through the Component interface uniformly.
✓ Primitive objects can be composed into arbitrarily complex structures, which clients treat uniformly.
✓ New leaf or composite classes integrate automatically with existing structures.
✓ Simplifies client code — no need to distinguish primitives from containers.
✗ Can make designs overly general — hard to restrict which component types are allowed in a composite at compile time.
  • File system: files (leaves) and directories (composites) share a common interface
  • DOM (Document Object Model): each node (element, text, comment) is part of a tree handled uniformly
  • Organizational hierarchies: employees and managers share a common interface; a manager has direct reports
  • GUI widget toolkits: buttons (leaves) and panels (composites containing buttons) are both Widgets
  • Expression trees in compilers: constants, variables (leaves) and operators (composites)
  • Menu systems: menu items and sub-menus share a common interface
09 · Object Structural
Decorator
Also known as: Wrapper
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
+

Subclassing is the traditional way to add behavior — but if you have many independent extensions that can be combined freely, the number of subclasses explodes (e.g., ScrollableTextView, BorderedTextView, ScrollableBorderedTextView …). Decorator wraps an object in a conforming wrapper that adds behavior before/after forwarding requests, and wrappers can be stacked arbitrarily.

Classic example: a text view that can optionally have a border and/or scrollbars. Rather than subclassing for each combination, BorderDecorator and ScrollDecorator wrap any Component, adding their embellishment and delegating to the inner component. Stacking them gives you any combination at runtime.

Component
Defines the interface for objects that can have responsibilities added dynamically.
ConcreteComponent
The base object to which responsibilities are added.
Decorator
Maintains a reference to a Component; forwards requests to it (conforming to the Component interface).
ConcreteDecorator
Adds specific responsibilities before/after forwarding to the component.

Both extend behavior, but Decorator does so dynamically — you can change an object's responsibilities at runtime. Inheritance is static and applies to all instances of the class. Decorator is also more granular and composable: two decorators can be combined independently.

✓ More flexible than static inheritance — mix and match behaviors at runtime.
✓ Avoids feature-laden base classes — each decorator adds exactly one responsibility.
✗ Produces many small objects — systems of decorators can be hard to debug (peel layers of wrappers).
✗ A decorated component isn't identical to the component itself — object identity matters.
  • Java I/O streams: new BufferedReader(new InputStreamReader(new FileInputStream(...)))
  • Python function decorators: @cache, @retry, @log stacked on any function
  • Web middleware pipelines: authentication → logging → rate-limiting → compression wrapping a request handler
  • Coffee ordering: Espresso + Milk + WhipCream — each add-on decorates the base drink
  • React Higher-Order Components (HOCs) adding behavior to any component
  • HTTP response decorators adding caching, compression, or security headers
10 · Object Structural
Facade
Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
+

Complex subsystems are hard to use correctly — they have many classes, many dependencies, and subtle interaction protocols. A Facade provides a simple interface to the subsystem, shielding clients from the complexity. The Facade doesn't hide the subsystem (you can still access it directly if needed), but provides a convenient default view.

This is especially valuable when you want to layer a system — higher-level layers use subsystems only through their facades. Layering minimizes dependencies between subsystems, making the system easier to evolve.

Facade
Knows which subsystem classes are responsible for a request; delegates client requests to appropriate subsystem objects.
Subsystem classes
Implement subsystem functionality; have no knowledge of the facade.
✓ Shields clients from subsystem components — reduces the number of objects clients deal with.
✓ Promotes weak coupling between subsystem and clients — change the subsystem without changing the facade interface.
✓ Layers a complex system cleanly.
✗ Can become a "god object" if not kept focused — the facade itself might accumulate too much logic.
  • Compiler front-end: one Compiler.compile(source) call hides lexer, parser, semantic analyzer, code generator
  • Home theater system: one remote "Watch Movie" button coordinates projector, stereo, lights, Blu-ray player
  • Service layer in layered architecture: controllers talk to services, not repositories/DAOs directly
  • SDK/library APIs simplifying complex platform features (e.g., a Camera facade hiding complex AVFoundation APIs)
  • E-commerce checkout: one placeOrder() method handles inventory, payment, shipping, notifications
  • React's useContext hook acting as a facade over the complex Context API machinery
11 · Object Structural
Flyweight
Use sharing to support large numbers of fine-grained objects efficiently.
+

When an application uses huge numbers of similar fine-grained objects, the memory overhead per object is prohibitive. Flyweight separates intrinsic state (shared, context-independent) from extrinsic state (context-dependent, passed in at call time). One shared flyweight object represents many logical objects; clients supply the extrinsic state when needed.

Classic example: a text editor treating every character as an object. There are only ~100 characters in ASCII but millions of character objects in a document. Flyweight shares one object per unique character (its font/glyph data is intrinsic); the position in the document (extrinsic) is supplied by the row/column data structure.

Flyweight
Declares an interface through which flyweights can receive and act on extrinsic state.
ConcreteFlyweight
Implements Flyweight; stores intrinsic state. Must be sharable.
FlyweightFactory
Creates and manages flyweight objects; ensures they are shared properly.
Client
Maintains references to flyweights; computes or stores extrinsic state.
✓ Drastically reduces the number of objects — can save orders of magnitude of memory.
✗ May introduce runtime costs — extrinsic state must be computed and passed to flyweights on every operation.
✗ Complicates code — clients must externalize state that was previously internal to objects.
  • Game particle systems: thousands of bullets/sparks sharing mesh/texture data, with position as extrinsic state
  • Font rendering: glyph data is shared; position on screen is extrinsic
  • Java's Integer.valueOf() caches instances for -128 to 127
  • String interning (Python, Java): identical string literals share one object
  • Map tile systems: tile image data is shared; map coordinates are extrinsic
  • Connection pool objects: shared connection configurations with per-request session state extrinsic
12 · Object Structural
Proxy
Also known as: Surrogate
Provide a surrogate or placeholder for another object to control access to it.
+

A proxy provides the same interface as the real subject but adds a level of indirection. Common uses:

Virtual Proxy: Creates expensive objects on demand (lazy initialization). Example: a large image is represented by a placeholder proxy that only loads the real image when it is actually drawn.

Remote Proxy: Provides a local representative for an object in a different address space (e.g., a stub in RPC/RMI).

Protection Proxy: Controls access to an object based on permissions. Checks caller rights before forwarding.

Smart Reference: Performs additional actions when an object is accessed — counting references, locking, logging.

Subject
Defines the common interface for RealSubject and Proxy.
RealSubject
The real object the proxy represents.
Proxy
Maintains a reference to RealSubject; controls access; may create or delete it.

Both wrap an object and conform to the same interface. The intent differs: Proxy controls access to the subject (who, when, if). Decorator adds responsibilities (what). A proxy doesn't change the subject's interface or add new functionality — it manages access to the same functionality.

  • Java RMI stubs — proxy objects in the client represent remote server objects
  • Hibernate lazy loading — proxy objects load database records on first access
  • CDN (Content Delivery Network) — a CDN edge server is a caching proxy for the origin
  • API gateways proxying requests to microservices with auth, rate limiting, and routing
  • JavaScript's Proxy object intercepts and redefines operations on objects
  • Security firewalls acting as access-control proxies for network resources
Behavioral

Behavioral Patterns

Behavioral patterns are concerned with algorithms and the assignment of responsibilities between objects. They describe not just patterns of objects or classes, but also the patterns of communication between them — characterizing complex control flow that's difficult to follow at runtime.

These patterns shift your focus away from control flow to the way objects are interconnected. Class-level behavioral patterns use inheritance to distribute behavior (Template Method, Interpreter). Object-level patterns use composition and delegation, letting peer objects cooperate to perform tasks that no single object can carry out alone.

A central theme: encapsulate what varies — an algorithm, a request, a state, an operation — in an object, and let it vary independently.

Key Themes

  • Encapsulate algorithms and requests as objects
  • Decouple senders from receivers
  • Define object interaction protocols
  • Distribute responsibilities flexibly
  • Support undo, traversal, and state management
13 · Object Behavioral
Chain of Responsibility
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
+

A request needs to be processed, but the sender doesn't know which object should handle it, or multiple objects may be candidates. Chain of Responsibility links handlers in a chain; each handler either processes the request or forwards it to the next. The sender remains blissfully unaware of who handled it.

Classic example: a context-sensitive help system. Clicking a Print button should show help specific to that button; if none exists, the dialog's help; if none, the application's general help. The button, dialog, and application form a chain — each handles the request if it can, otherwise passes it up.

Handler
Defines interface for handling requests; optionally implements the successor link.
ConcreteHandler
Handles requests it's responsible for; otherwise forwards to successor.
Client
Initiates request to a ConcreteHandler on the chain.
✓ Decouples sender from receiver — sender only needs to know the first handler.
✓ Added flexibility — handlers can be added, removed, or reordered at runtime.
✗ No guarantee of handling — a request may fall off the end of the chain unhandled.
✗ Debugging can be hard — tracing a request through a long chain requires understanding the whole chain.
  • Event propagation in browsers: click events bubble from child to parent elements
  • Java Servlet filters and Spring interceptor chains processing HTTP requests
  • Exception handling: try/catch blocks form a chain of responsibility
  • Logging levels: DEBUG → INFO → WARN → ERROR handlers
  • Approval workflows: expense claim goes to team lead → manager → CFO until approved
  • ATM cash dispensing: tries to dispense with $100 bills, then $20, then $10, etc.
14 · Object Behavioral
Command
Also known as: Action, Transaction
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
+

A UI button doesn't know what to do when clicked — that depends entirely on context. Instead of hard-coding the action, a Command object encapsulates the request: who receives it, which operation to invoke, and with what arguments. The button just calls execute().

This separation enables: (1) parameterizing actions at runtime, (2) queuing commands for later execution, (3) logging for crash recovery, and most powerfully, (4) undo/redo by reversing execute() with an unexecute() and maintaining a history stack.

Command
Declares the execute() interface.
ConcreteCommand
Binds a Receiver to an action; implements execute() by calling operations on Receiver.
Client
Creates a ConcreteCommand and sets its receiver.
Invoker
Asks the command to carry out the request.
Receiver
Knows how to perform the operations associated with the request.
✓ Decouples invoker from receiver — invoker knows nothing about how a request is performed.
✓ Commands are first-class objects — they can be queued, logged, serialized, composed (MacroCommand).
✓ Undo/redo support — maintain a history list and call unexecute() in reverse.
✓ Easy to add new commands — no existing classes change.
✗ Can lead to many small Command classes for every distinct operation.
  • Text editor undo/redo — every edit (insert, delete, format) is a Command on a history stack
  • GUI menu items and toolbar buttons parameterized with Command objects
  • Database transactions — a command encapsulates operations that commit or rollback atomically
  • Message queues — commands serialized and consumed by workers asynchronously
  • Macro recording — recording a sequence of user actions as a replayable list of commands
  • Remote controls — each button is a Command bound to a device action
  • Job schedulers — scheduled tasks as Command objects executed at a later time
15 · Class Behavioral
Interpreter
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
+

When a type of problem recurs frequently enough that it's worth expressing instances as sentences in a simple language, Interpreter represents the grammar as a class hierarchy and builds an abstract syntax tree (AST) from those classes. Each class in the hierarchy implements an interpret() operation. Evaluating the tree interprets the expression.

Classic example: regular expressions. Define grammar classes for LiteralExpression, AlternationExpression, SequenceExpression, RepetitionExpression. A regex like raining & (dogs | cats)* becomes an AST. Calling interpret(inputString) on the root checks for a match.

AbstractExpression
Declares abstract interpret() operation common to all AST nodes.
TerminalExpression
Implements interpret() for terminal symbols (base cases of recursion).
NonterminalExpression
One class per grammar rule; holds child expressions; calls interpret() recursively on them.
Context
Global information for the interpreter (e.g., input string being matched).
Client
Builds and invokes the AST.

Use when: the grammar is simple and sentences in the language need to be interpreted frequently. The class hierarchy maps directly to grammar rules, making it easy to extend.

Avoid when: the grammar is complex (classes proliferate, maintenance becomes painful — use parser generators like ANTLR instead) or performance is critical (interpret AST directly is slower than compiled approaches).

  • SQL parsers and query evaluators interpreting SQL expressions
  • Regular expression engines
  • Mathematical expression evaluators (calculators, formula engines)
  • Configuration language interpreters (JSON/YAML schema evaluation)
  • Scripting language interpreters embedded in applications
  • Rule engines evaluating business rules expressed in a simple DSL
16 · Object Behavioral
Iterator
Also known as: Cursor
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
+

An aggregate (list, tree, set) should expose its elements for traversal without revealing its internal data structure. It should also support multiple simultaneous traversals and different traversal strategies (forward, reverse, filtered). Iterator takes traversal responsibility out of the aggregate and into a separate iterator object.

Key operations: First(), Next(), IsDone(), CurrentItem(). The aggregate provides a factory method to create iterators, keeping traversal decoupled from the data structure.

Iterator
Defines interface for accessing and traversing elements.
ConcreteIterator
Implements the Iterator; tracks current position in traversal.
Aggregate
Defines interface for creating an Iterator object.
ConcreteAggregate
Implements Iterator creation, returning an instance of the appropriate ConcreteIterator.
✓ Supports multiple simultaneous traversals — each iterator object holds its own traversal state.
✓ Simplifies the aggregate interface — traversal code isn't mixed into the collection.
✓ Uniform interface across different collection types.
✗ External iterators give more control but require the client to advance the traversal — more error-prone than internal iterators.
  • Java's Iterator<T> and the enhanced for-each loop (Iterable interface)
  • Python's iterator protocol and generators (yield creates lazy iterators)
  • JavaScript's iterable protocol (Symbol.iterator) used by for…of loops
  • Database cursor — iterating over query results without loading all rows into memory
  • File system walkers traversing directory trees
  • Stream processing pipelines (Java Streams, .NET LINQ, Kotlin Sequences)
17 · Object Behavioral
Mediator
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
+

When many objects interact with many other objects, the resulting tangle of references makes the system hard to reuse and change. A Mediator centralizes and controls all interactions. Objects communicate with the mediator rather than with each other directly. This turns an N×N mesh of connections into N spokes on a hub.

Classic example: a dialog box with interdependent widgets. A checkbox enables/disables a text field; a list selection updates a button label; etc. Instead of each widget knowing about all others, they notify the DialogDirector (mediator), which coordinates the response. Each widget stays simple and reusable.

Mediator
Defines an interface for communicating with Colleague objects.
ConcreteMediator
Implements cooperative behavior by coordinating Colleague objects; knows and maintains them.
Colleague
Each Colleague knows its Mediator; communicates with other colleagues only via the mediator.

Both abstract relationships between classes. Facade is unidirectional — it simplifies the interface to a subsystem for clients. Mediator is bidirectional — it mediates interactions among the objects in the system. Facade objects don't know each other; Mediator colleagues communicate through the mediator.

  • Air traffic control tower: planes communicate through the tower, not directly with each other
  • Chat room server: messages between users pass through the chat server
  • MVC: the Controller mediates between Model and View
  • Redux/Flux store: components dispatch actions to the store; the store notifies subscribers
  • UI dialog forms with complex field interdependencies
  • Event bus / message broker in event-driven architectures
18 · Object Behavioral
Memento
Also known as: Token
Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
+

Undo requires saving an object's state. But saving state directly exposes internal implementation — breaking encapsulation. Memento solves this by letting the Originator create a Memento containing a snapshot of its own private state. The Caretaker holds the memento without ever accessing its contents. To undo, the Originator restores itself from the memento.

The Memento defines two interfaces: a narrow one for Caretakers (opaque, no access to contents) and a wide one for Originators (full access). This keeps state internal while externalizing it safely.

Originator
Creates a Memento of its internal state; uses the Memento to restore that state.
Memento
Stores the internal state of the Originator. Two interfaces: wide for Originator, narrow for Caretaker.
Caretaker
Holds the Memento safely without examining or modifying its contents.
✓ Preserves encapsulation — internal state is snapshotted without exposing implementation.
✓ Simplifies Originator — state-saving logic stays in the Originator, not scattered in clients.
✗ Mementos may be expensive — deep copying large state can be costly in time and memory.
✗ Caretakers must manage memento lifecycle carefully (when to keep vs. discard).
  • Text editor undo — each typing action's pre-state is saved as a memento
  • Game save points — full game state serialized and stored for later restoration
  • Database transaction savepoints — rollback to a specific point within a transaction
  • Browser history — each page visit stores navigation state for back/forward navigation
  • Version control system commits — each commit is a memento of the repository state
  • Wizard-style forms — saving intermediate form state to navigate back without data loss
19 · Object Behavioral
Observer
Also known as: Publish-Subscribe, Dependents
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
+

When one object (the Subject/Model) changes state and an unknown number of other objects (Observers/Views) must be updated accordingly, hard-coding the dependencies creates tight coupling. Observer lets the Subject maintain a list of registered observers and notify all of them on change, without knowing their concrete types or count.

This is the core of MVC: the Model is the Subject; Views are Observers. A single Model change automatically refreshes all open views — a spreadsheet, a histogram, and a pie chart — simultaneously.

Subject
Knows its observers; provides interface to attach/detach/notify observers.
Observer
Defines update interface called when Subject's state changes.
ConcreteSubject
Stores the state of interest; calls Notify() when state changes.
ConcreteObserver
Maintains a reference to Subject; implements Update to stay consistent with Subject's state.

Push: Subject sends detailed state data in the notification. Simpler for observers but Subject must know what data observers need.

Pull: Subject sends a minimal notification; observers query the Subject for the state they need. More decoupled, but observers may make unnecessary queries.

  • MVC frameworks — model notifies views of changes
  • DOM event listeners — addEventListener registers observers on elements
  • React's useState / Redux store subscriptions notify components to re-render
  • Message queues and event buses — publishers notify multiple subscribers
  • Stock ticker systems — price changes notify all registered displays and alerts
  • Spreadsheet cells — formula cells observe source cells and recalculate when they change
  • News feeds / webhooks — systems subscribing to external event streams
20 · Object Behavioral
State
Also known as: Objects for States
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
+

When an object's behavior depends heavily on its state, the naive approach is large conditional statements scattered throughout methods. State encapsulates each state in an object and delegates state-dependent behavior to the current State object. The context delegates requests to its current state; transitioning to a new state just changes the state object reference.

Classic example: a TCP connection in states Established, Listening, Closed. Rather than conditional logic in every method, delegate to EstablishedState, ListeningState, ClosedState objects. Each handles operations differently; each handles state transitions.

Context
Defines the interface clients care about; maintains a ConcreteState instance defining current state.
State
Defines the interface for encapsulating behavior associated with a particular state.
ConcreteState
Each subclass implements behavior for a particular state of the Context.

Both delegate behavior to a separate object. State transitions between states automatically — the state objects know about each other. Strategy is chosen by the client and stays stable — strategies don't switch themselves. State models a lifecycle; Strategy models interchangeable algorithms.

  • TCP/IP connection states (Closed, Listening, Established, Time-wait)
  • Vending machine states (Idle, HasMoney, Dispensing, OutOfStock)
  • Traffic light controller cycling through Red → Green → Yellow
  • Document workflow states (Draft → Review → Published → Archived)
  • Media player states (Playing, Paused, Stopped, Loading)
  • Game character states (Idle, Walking, Jumping, Attacking, Dead)
  • Order fulfillment lifecycle (Pending → Confirmed → Shipped → Delivered → Returned)
21 · Object Behavioral
Strategy
Also known as: Policy
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
+

When multiple algorithms exist for a task and clients need to switch between them, hard-coding algorithm selection (or using conditionals) makes the code rigid and bloated. Strategy encapsulates each algorithm in its own class behind a common interface. The Context holds a Strategy reference and delegates the operation to it. To change the algorithm, swap the Strategy object.

Classic example: a text compositor supporting different line-breaking strategies (simple, TeX-quality, no-break). The compositor delegates to an interchangeable Compositor strategy: SimpleCompositor, TeXCompositor. Changing composition quality at runtime just swaps the strategy.

Strategy
Declares the interface common to all supported algorithms.
ConcreteStrategy
Implements the algorithm using the Strategy interface.
Context
Is configured with a ConcreteStrategy; maintains a reference to a Strategy; calls the strategy interface.
✓ Eliminates conditional statements for selecting algorithms.
✓ Algorithms can be switched at runtime.
✓ Alternative implementations of an algorithm are easy to add without modifying context code.
✗ Clients must be aware of different Strategies to choose the right one.
✗ Increased number of objects — one class per algorithm.
  • Sorting algorithms: Java's Comparator passed to Collections.sort()
  • Payment processing: CreditCard, PayPal, Crypto strategies implementing a common payment interface
  • Data compression: LZW, Deflate, Brotli strategies behind a Compressor interface
  • Navigation apps: routes via car, walking, public transit are interchangeable routing strategies
  • Machine learning: different training algorithms (SGD, Adam, RMSProp) as interchangeable optimizers
  • Logging: file, console, remote strategies behind a Logger interface
  • Tax calculation: different tax strategies per country/region
22 · Class Behavioral
Template Method
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
+

When several classes share the same algorithm skeleton with different implementations of specific steps, the common structure can be factored into an abstract base class. The template method in the base class calls abstract "hook" operations — steps subclasses must override — while keeping the overall algorithm in one place.

Classic example: a report generator with fixed steps: open file → parse data → print header → print body → print footer → close file. The template method controls this order. Subclasses only override steps like printHeader() and printBody() to customize behavior for specific report types.

AbstractClass
Defines abstract primitive operations that subclasses implement; implements a template method defining the algorithm skeleton.
ConcreteClass
Implements primitive operations to carry out the subclass-specific steps.

Both vary parts of an algorithm. Template Method uses inheritance — the invariant parts are in the base class, varying parts in subclasses. This is a compile-time choice. Strategy uses composition — the whole algorithm is encapsulated in a separate object, swappable at runtime. Template Method is simpler but less flexible.

  • Java's AbstractList — provides template methods; subclasses implement get() and size()
  • JUnit's test lifecycle: setUp()test*()tearDown() is a template method
  • Servlet's HttpServlet: service() dispatches to doGet(), doPost() etc.
  • Build systems: compile → test → package → deploy as a template, each step overridden per language
  • Report generation pipelines with fixed structure but customizable sections
  • Data import pipelines: open source → validate → transform → load (ETL skeleton)
23 · Object Behavioral
Visitor
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
+

When you need to perform many distinct, unrelated operations on an object structure (a Composite tree, for example), and you don't want to pollute each element class with all those operations, Visitor externalizes the operations. Each element implements accept(Visitor) — a double dispatch mechanism that calls the right visitXxx() method on the visitor for the element's concrete type.

Classic example: a document composed of Character, Image, and Row elements. Adding spell-checking, hyphenation, and word-count operations would require modifying all element classes each time. With Visitor, each new operation is a new Visitor subclass. Element classes never change.

Visitor exploits double dispatch: the operation performed depends on both the type of the Visitor and the type of the element. When an element calls visitor.visitMyType(this), the visitor's overloaded method for that type is called. This effectively simulates method dispatch based on two types.

Visitor
Declares a visit operation for each ConcreteElement class in the structure.
ConcreteVisitor
Implements each operation declared by Visitor; accumulates state as elements are visited.
Element
Defines accept(Visitor) operation.
ConcreteElement
Implements accept() by calling visitor.visitConcreteElement(this).
ObjectStructure
Can enumerate its elements; provides interface for visitors to visit its elements.

Use when: the object structure is stable (rarely changes) but you frequently need new operations on it. Adding a new visitor is easy; adding a new element type requires updating all visitors.

Avoid when: the class hierarchy changes frequently — every new element type requires updating every Visitor interface and all implementations.

  • Compilers: AST visitors for type-checking, optimization, code generation, pretty-printing
  • XML/JSON document processors visiting each node type differently
  • Tax calculators visiting different types of financial instruments (stocks, bonds, real estate)
  • Game engine component systems visiting entities with different component combinations
  • Report generators applying different formatting operations to different document elements
  • Static analysis tools scanning code ASTs for different categories of issues