Behavioral Patterns «Prev Next»

Lesson 1

Behavioral Design Patterns

Behavioral design patterns describe how objects and classes interact and divide responsibilities among themselves. A behavioral pattern abstracts an action from the object or class that performs it. By changing the object or class, you change the algorithm used, the objects affected, or the behavior, while preserving the same basic interface for client classes.

Behavioral patterns form the largest category in the GoF catalog: eleven of the twenty-three GoF patterns are behavioral. The key to understanding behavioral patterns is communication. The focus shifts from the objects and classes themselves to how those objects and classes communicate with one another. In the truest form of composition, behavioral patterns are best understood in terms of how objects work together to perform tasks that no single object can carry out alone.

How Objects and Classes Interact

This module explores behavioral design patterns: patterns that describe the way objects and classes interact and divide responsibilities among themselves. A good toolbox of behavioral patterns allows you to solve many challenging problems you are likely to encounter when designing object-oriented systems, including enumerating lists, responding to changes of state in an object, and serializing or deserializing objects without penetrating data encapsulation.

In this module, you will learn:

  1. How programmers use behavioral design patterns
  2. About the most commonly used behavioral design patterns
  3. When to use the Observer and Mediator patterns
  4. How to use the Mediator pattern to manage different traffic light states
  5. How modern Java APIs including java.util.concurrent.Flow, functional interfaces, and lambda expressions relate to the GoF behavioral patterns

Behavioral object patterns use object composition rather than inheritance. Some patterns describe how a group of peer objects cooperate to perform a task that no single object can carry out by itself. An important design question is how peer objects know about each other. Peers could maintain explicit references to each other, but that increases coupling. In the extreme, every object would know about every other.

The Mediator pattern avoids this by introducing a mediator object between peers. The mediator provides the indirection needed for loose coupling.

The Chain of Responsibility provides even looser coupling. It lets you send requests to an object implicitly through a chain of candidate objects. Any candidate may fulfill the request depending on runtime conditions. The number of candidates is open-ended, and you can select which candidates participate in the chain at runtime.

Behavioral Patterns and Communication

Behavioral patterns are concerned with algorithms and the communication between objects that carry them out. They identify common communication patterns between objects and increase flexibility in how that communication is carried out. Behavioral patterns are typically used to:

  • Decouple senders and receivers of messages
  • Encapsulate behavior in objects
  • Implement complex control flow

Several concrete examples show how behavioral patterns improve communication design in real systems:

  • The Chain of Responsibility pattern implements a workflow system where different tasks are handled by different handler objects in the chain. Each handler decides whether to process the request or pass it along.
  • The Command pattern implements an undo/redo system where requests are encapsulated as objects that can be queued, logged, and reversed or reapplied later.
  • The Mediator pattern implements a user interface where different controls communicate with each other through a central mediator object rather than holding direct references to one another.

The Eleven GoF Behavioral Patterns

Behavioral design patterns make up the largest section of the GoF catalog. The Gang of Four defined eleven behavioral patterns:

  • Chain of Responsibility: creates a chain of handler objects to process requests. Each handler decides whether to process the request itself or pass it to the next handler in the chain.
  • Command: encapsulates a request as an object, letting you parameterize clients with different requests, queue or log requests, and support undoable operations. It decouples the object that invokes the operation from the one that knows how to perform it. In modern Java, java.lang.Runnable and java.util.concurrent.Callable are standard Command implementations.
  • Interpreter: defines a grammatical representation for a language and provides an interpreter to evaluate sentences in that language. Used for parsing and interpreting specialized languages or expression trees.
  • Iterator: provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation. In modern Java, java.lang.Iterable and java.util.Iterator are the standard library implementations, and the enhanced for-each loop is built on this pattern.
  • Mediator: defines an object that encapsulates how a set of objects interact. It promotes loose coupling by keeping objects from referring to each other explicitly, allowing their interaction to vary independently.
  • Memento: captures and externalizes an object's internal state so that the object can be restored to that state later without violating encapsulation. The foundation of undo mechanisms and snapshot-based state management.
  • Observer: defines a one-to-many dependency between objects so that when one object's state changes, all its dependents are notified and updated automatically. Commonly used for event handling and reactive systems. In modern Java, java.util.concurrent.Flow (Java 9+) is the standard reactive Observer implementation, replacing the deprecated java.util.Observable.
  • State: allows an object to alter its behavior when its internal state changes. The object appears to change its class because its behavior changes completely based on state.
  • Strategy: defines a family of algorithms, encapsulates each one, and makes them interchangeable. The algorithm varies independently from the clients that use it. In modern Java, functional interfaces and lambda expressions are the idiomatic Strategy implementation: a Comparator lambda passed to Collections.sort() is a Strategy.
  • Template Method: defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps without changing the overall structure. In modern Java, interface default methods (Java 8+) provide an alternative to the abstract class Template Method for defining shared algorithmic structure.
  • Visitor: represents an operation to be performed on the elements of an object structure. Visitor lets you define new operations without changing the classes of the elements on which it operates. In Java 21+, sealed classes with pattern matching in switch expressions provide a modern alternative to the classic Visitor double-dispatch mechanism.

The key to understanding behavioral design patterns is communication. The focus shifts from the individual objects and classes that make up a pattern to the communication between them. Behavioral patterns are best understood in terms of how objects work together to perform tasks.

Behavioral patterns focus on communication between pattern participants
Figure 6-1: Behavioral patterns focus on communication between pattern participants

The emphasis on interaction is so significant that some class diagrams look identical. The State and Strategy patterns, for example, share a nearly identical class diagram structure. However, because of the way their participants communicate and handle responsibilities, the two patterns are very different in intent and application.


SEMrush Software 1 SEMrush Banner 1