Behavioral Patterns «Prev Next»

Lesson 4Common behavioral patterns
ObjectiveDescribe the Common Behavioral Patterns

Common Behavioral Patterns in Java

The Gang of Four (GoF) organized their catalog of design patterns into three families: creational patterns, which deal with how objects are created; structural patterns, which deal with how objects and classes are composed into larger structures; and behavioral patterns, which deal with how objects communicate, interact, and divide responsibility among themselves. This lesson describes the common behavioral patterns and explains what they have in common.

Where a creational pattern answers the question "how is this object made?" and a structural pattern answers "how are these objects assembled?", a behavioral pattern answers a different question entirely: "how do these objects talk to one another, and who is responsible for what?" That focus on communication and the assignment of responsibility is the thread that ties every pattern in this lesson together. Seven behavioral patterns appear again and again in real systems: Chain of Responsibility, Command, Iterator, Mediator, Observer, Strategy, and Visitor. The rest of this lesson introduces each one, then steps back to show how they relate to and combine with each other.

How Behavioral Patterns Shape Object Interaction

In the context of the Gang of Four, behavioral patterns are design patterns that focus primarily on the communication and interaction between objects and classes. Their goal is to achieve greater flexibility and organization in a software system by defining, clearly and reusably, how responsibilities are distributed among the objects that make it up. Rather than concentrating logic in one place, these patterns spread it across collaborating objects and then specify exactly how those objects coordinate.

Consider the Observer pattern as an illustration. It creates a one-to-many dependency between objects, so that a change in one object leads to automatic updates in the objects that depend on it. This is the foundation of distributed event handling systems, where many parts of a program need to be notified when something changes elsewhere. The Strategy pattern illustrates a different kind of interaction: it encapsulates an algorithm inside its own class, allowing an object to change its behavior at runtime simply by selecting a different strategy. Because the client code works against an interface or abstract class rather than a concrete implementation, behaviors can be swapped freely without altering the client. That is loose coupling in practice.

The Command pattern encapsulates a request as an object. Once a request is an object, it can be passed as a parameter, placed on a queue, written to a log, or reversed to support undo. Command decouples the object that invokes an operation from the object that knows how to carry it out, which is why user interface frameworks lean on it so heavily: clicks, key presses, and menu selections can all be treated uniformly as command objects. The Chain of Responsibility pattern passes a request along a chain of handlers, each of which decides either to process the request or to forward it to the next handler. It fits any scenario where several objects might handle a request and the actual handler is not known until runtime, such as logging frameworks or event processing pipelines. Through patterns like these, the GoF provides tested models for how objects can interact in ways that promote reusability, extensibility, and robustness.

The Seven Common Behavioral Patterns

The image below summarizes the seven patterns covered in this lesson. Each is described once in the paragraphs that follow, in the same order, with a link to its dedicated page for a deeper treatment.

The seven common Java behavioral design patterns.

1. Chain of Responsibility

The Chain of Responsibility pattern describes a system in which several objects each receive an opportunity to handle a request. The request propagates along the chain until some object handles it, allowing an even further decoupling between classes because the sender does not need to know which receiver will ultimately act. The Java 1.0 event model was based on this design pattern. It is well suited to routing, authorization, and logging logic, where the correct handler is determined at runtime rather than fixed in advance.

2. Command

The Command pattern encapsulates a request in an object so that it can be passed as a parameter, stored on a history list, queued, logged, or undone. By separating the execution of a command from the interface environment that produced it, Command lets an application treat every user action uniformly and makes features like undo and redo natural to implement.

3. Iterator

The Iterator pattern formalizes the way we move through the elements of a collection, whether that collection is a set, a list, an array, or a hash table. It provides an abstract means of passing through each element in turn, and it separates the enumeration of a collection from the way the collection is actually stored, so client code can traverse very different data structures through one consistent interface.

4. Mediator

The Mediator pattern is perhaps the most common and useful behavioral pattern. It allows many objects, of the same or of different classes, that need to communicate with each other to each communicate only with a single, central mediator. Instead of every class knowing about every other class, each one knows only the mediator, which simplifies communication and keeps the individual classes from having to know about one another.

5. Observer

The Observer pattern allows an observer object to notice and react to changes in an observed object. Each observed object maintains a list of its observers and notifies each of them whenever its relevant state changes. This defines the way a number of classes can be told about a change at once. The Java 1.1 event model is based on this design pattern.

6. Strategy

The Strategy pattern encapsulates an algorithm inside an object and makes it easy to specify and change the algorithm an object uses. Different algorithms live in different strategy objects, each of which can be plugged into a context object to change its behavior. Because strategies can be swapped at runtime, the same object can be adjusted to fit the needs of a specific situation without rewriting it.

7. Visitor

The Visitor pattern lets you define a new operation without changing the classes of the elements on which it operates. It encapsulates behavior that would otherwise be scattered across many classes into a single visitor object, which can then traverse and operate on an object structure, in effect adding function to a set of classes from the outside.

One further pattern is worth naming here: the State pattern, which encapsulates the states of an object so that the object changes its behavior when its state object changes, is another behavioral pattern commonly grouped with the seven above.

Relationships Between the Patterns

Although each of these patterns is useful on its own, they are not isolated ideas. They can be grouped by the problem they address, and seeing those groupings makes it easier to choose the right pattern for a given job.

Decoupling Senders and Receivers: Chain of Responsibility and Command

Chain of Responsibility and Command are both concerned with decoupling the senders and receivers of requests. In Chain of Responsibility, a request is passed along a chain of potential handlers until one of them handles it, so the sender never needs to know which handler responds. In Command, a request is encapsulated in an object that can be passed around and executed later, so the sender is separated from the receiver in time as well as in space. Both patterns free the originator of a request from any knowledge of who will ultimately carry it out.

Loose Coupling Between Communicating Objects: Mediator and Observer

Mediator and Observer are both concerned with loosely coupling objects that need to communicate with each other. In Mediator, all communication between objects flows through a central mediator object, so no object needs a direct reference to any other. In Observer, objects can subscribe to and unsubscribe from notifications published by other objects, so a publisher never needs to know the concrete identity of its subscribers. In both cases, objects coordinate without being rigidly bound together.

Interchangeable Behavior: Strategy and Visitor

Strategy and Visitor are both concerned with encapsulating behavior in objects and making it interchangeable. In Strategy, different algorithms are implemented in different strategy objects, which can be plugged into a context object to change its behavior. In Visitor, different operations are implemented in different visitor objects, which can be used to traverse and operate on object structures. In each pattern, the behavior lives in a separate, swappable object rather than being hard-wired into the class that uses it.

Combining Patterns in Practice

Because these patterns share a focus on communication and responsibility, they combine naturally. A few pairings appear often enough to be worth knowing by name.

Chain of Responsibility and Mediator: Dynamic Mediated Routing

Chain of Responsibility and Mediator can be used together to create a dynamic chain of handlers that is coordinated by a central mediator object. The mediator decides how the chain is assembled and which handlers participate, which is useful for implementing complex routing or authorization logic where the set of handlers changes at runtime.

Command and Observer: Undo and Redo

Command and Observer can be used together to implement undo and redo functionality. When a command is executed, it notifies its observers of the change. If the command is later undone, the observers are notified again so they can restore the previous state. The Command objects carry the history, and the Observer relationships keep the rest of the system in step with it.

Strategy and Visitor: Generic Algorithms

Strategy and Visitor can be used together to implement generic algorithms. A generic sorting algorithm, for example, could use a visitor to compare and swap the elements of a collection while a strategy determines the ordering rule. The algorithm stays the same; the pluggable objects supply the specifics.

Taken as a whole, the common behavioral patterns are a powerful set of tools for designing flexible and extensible software. By understanding the relationships between them, you can choose the right pattern for a given problem and combine them in creative ways. The lessons that follow examine several of these patterns individually and in greater depth.

Common Behavioral Patterns - Quiz

Here is a short quiz on the material we have just covered.
Common Behavioral Patterns - Quiz

SEMrush Software 4 SEMrush Banner 4