Behavioral Patterns
Learn how Java behavioral patterns shape runtime collaboration, state changes, event flow, and decision boundaries between objects.
Behavioral patterns are about collaboration over time. They matter when the main design pressure is no longer object creation or structural wrapping, but how decisions are made, how behavior changes, and how messages move through a system.
In Java, this chapter is not just about memorizing classical names. It is about recognizing recurring runtime design pressures:
- choose one of several algorithms cleanly
- let behavior change when internal state changes
- coordinate many participants without every class knowing every other class
- propagate events without hard-wiring all observers directly
- express commands, rules, or workflows in a form the rest of the system can reason about
Some behavioral patterns remain close to their classic form. Others look different in modern Java because lambdas, streams, listeners, reactive APIs, dependency injection, and framework callbacks have changed how behavior is packaged.
The chapter is strongest if you read each pattern with three questions in mind:
- What runtime collaboration problem is this pattern solving?
- Is the pattern clarifying the flow of behavior, or only adding indirection?
- Would modern Java language or library features already solve most of the problem more directly?
In this section
- Introduction to Behavioral Patterns in Java
Understand what Java behavioral patterns solve, how they differ from structural and creational concerns, and how to choose among runtime collaboration styles.
- Chain of Responsibility Pattern
Use Chain of Responsibility in Java when a request should move through ordered handlers without hardwiring one receiver up front.
- Command Pattern
Use the Command pattern in Java when requests should be captured as objects that can be queued, logged, retried, or undone.
- Interpreter Pattern
Use the Interpreter pattern in Java for small, stable languages where explicit grammar objects are easier to evolve than ad hoc parsing logic.
- Implementing the Interpreter Pattern in Java
Build a small Java interpreter from grammar objects to evaluation logic, and understand when the pattern is preferable to ad hoc parsing.
- Advanced Interpreter Implementation Techniques in Java
Use ASTs, parsers, caching, and validation techniques to keep Java interpreters maintainable once a toy grammar turns real.
- Interpreter Pattern Performance Trade-Offs in Java
Review parsing, allocation, caching, and hybrid-compiler trade-offs before using the Interpreter pattern in performance-sensitive Java code.
- Interpreter Pattern Use Cases and Examples in Java
See where Interpreter fits in Java expression evaluators, config rules, and DSLs, and where a parser generator or compiler is the better tool.
- Iterator Pattern
Use the Iterator pattern in Java when traversal should stay separate from collection internals and clients need a stable way to walk data.
- Implementing Iterator in Java
Implement Java iterators when custom aggregates need explicit traversal without exposing their internal representation.
- Internal vs. External Iterators
Compare Java external iterators with callback- or stream-style internal iteration so traversal control stays intentional.
- Fail-Fast and Fail-Safe Iterators
Understand Java fail-fast and fail-safe iterator behavior so mutation and traversal expectations stay realistic.
- Enhancing Iterators
Extend Java iterators carefully when traversal needs filtering, peeking, or domain-specific movement without turning the cursor API into a grab bag.
- Iterator Pattern Use Cases and Examples in Java
See where Iterator genuinely helps in Java systems, especially for custom aggregates, trees, graphs, and domain-specific traversal order.
- Mediator Pattern
Use the Mediator pattern in Java when too many components coordinate directly and the collaboration rules need one explicit home.
- Memento Pattern
Use the Memento pattern in Java to capture restorable state without exposing internal representation, and know when snapshot cost becomes the real constraint.
- Implementing Memento in Java
Capture and restore Java object state without exposing internals, and decide how much snapshot responsibility belongs in each class.
- Originator, Memento, and Caretaker Roles in Java
Understand how Originator, Memento, and Caretaker divide responsibility so Java undo logic stays encapsulated and reviewable.
- Handling State Restoration in Java with Memento Pattern
Choose snapshot granularity, history retention, and restore semantics so Memento stays useful in Java without becoming a memory sink.
- Serialization with the Memento Pattern in Java
Learn when Java serialization can support memento-style snapshots and when custom state capture is safer and cheaper.
- Memento Pattern Use Cases and Examples in Java
See where Memento fits in undo stacks, editors, workflows, and transactional recovery, and where event logs or versioning are stronger choices.
- Observer Pattern with Modern Alternatives
Use Observer-style designs in Java when change notifications should fan out, while also understanding when listeners, streams, or pub-sub models are better fits.
- State Pattern
Use the State pattern in Java when behavior changes meaningfully with the object's current state and conditionals start obscuring the model.
- Strategy Pattern
Use the Strategy pattern in Java when caller-selected behavior should vary cleanly without piling conditionals into one class.
- Template Method Pattern
Use Template Method in Java when an algorithm skeleton should remain fixed while selected steps vary across subclasses.
- Visitor Pattern
Use the Visitor pattern in Java when operations should vary more often than the object structure they operate on.
- Null Object Pattern
Use Null Object in Java when a default no-op collaborator makes absence explicit and safer than scattered null checks.
- Specification Pattern
Use the Specification pattern in Java to encode business rules as reusable predicates that can be composed, tested, and translated across boundaries.