We’ve already been through a brief introduction to design patterns, and a description of the most important creational design patterns and structural design patterns. In this article we’ll take a look at the last category of design patterns: behavioral patterns.

Behavioral design patterns are concerned with the relationships among communications using different objects. They identify common communication patterns and provide a well-known solution to implement this communication, offering a higher degree of flexibility.

The most used behavioral patterns are:

Chain of responsibility

The Chain of responsibility Pattern can be used when there is a potentially high number of processing elements, and a stream of requests must be handled in different ways. Each request will be processed by different elements.

This pattern is implemented by encapsulating the processing elements inside a pipeline abstraction, and have objects launch and leave their requests at the entrance to the pipeline. The pattern chains the receiving objects together, and then passes any request messages from object to object until it reaches an object capable of handling the message.

Chain of Responsibility simplifies object interconnections. Instead of senders and receivers maintaining references to all candidate receivers, each sender keeps a single reference to the head of the chain, and each receiver keeps a single reference to its immediate successor in the chain

Command

The Command Pattern can be used when there is a need to issue requests to objects without knowing anything about the operation being requested or the receiver of the request.

Command decouples the object that invokes the operation from the one that knows how to perform it. To achieve this separation, the designer creates an abstract base class that maps a receiver (an object) with an action (a pointer to a member function). The base class contains an execute() method that simply calls the action on the receiver. All clients of Command objects treat each object as a “black box” by simply invoking the object’s virtual execute() method whenever the client requires the object’s “service”.

Command objects can be thought of as “tokens” that are created by one client that knows what needs to be done, and passed to another client that has the resources for doing it.

Interpreter

The Interpreter Pattern can be used when we’re facing a class of problems that occurs repeatedly in a well-defined and well-understood domain. If the domain were characterized with a “language”, then problems could be easily solved with an interpretation “engine”.

The Interpreter pattern discusses: defining a domain language (i.e. problem characterization) as a simple language grammar, representing domain rules as language sentences, and interpreting these sentences to solve the problem. The pattern uses a class to represent each grammar rule. And since grammars are usually hierarchical in structure, an inheritance hierarchy of rule classes maps nicely.

An abstract base class specifies the method interpret(). Each concrete subclass implements interpret() by accepting (as an argument) the current state of the language stream, and adding its contribution to the problem solving process.

Iterator

The Iterator Pattern can be used when there’s a need to “abstract” the traversal of very different data structures so that algorithms can be defined that are capable of interfacing with each transparently.

An aggregate object such as a list should give you a way to access its elements without exposing its internal structure. Moreover, you might want to traverse the list in different ways, depending on what you need to accomplish. But you probably don’t want to bloat the List interface with operations for different traversals, even if you could anticipate the ones you’ll require. You might also need to have more than one traversal pending on the same list. And providing a uniform interface for traversing many types of aggregate objects (i.e. polymorphic iteration) might be valuable.

The Iterator pattern lets you do all this. The key idea is to take the responsibility for access and traversal out of the aggregate object and put it into an Iterator object that defines a standard traversal protocol.

Mediator

When you have a big number of objects interacting among them, a rather complex structure might be formed. It can become so complex that trying to reutilize some functionality might show the spaghetti code phenomenon: trying to scoop a single serving results in an all or nothing clump. To avoid this, the Mediator Pattern encapsulates the behavior of the whole group in a single object.

Partitioning a system into many objects generally enhances reusability, but proliferating interconnections between those objects tend to reduce it again. The mediator object encapsulates all interconnections, acts as the hub of communication, is responsible for controlling and coordinating the interactions of its clients, and promotes loose coupling by keeping objects from referring to each other explicitly.

In this pattern, peers are not coupled to one another. Each one talks to the Mediator, which in turn knows and conducts the orchestration of the others. The many to many mapping between colleagues that would otherwise exist, has been promoted to full object status. This new abstraction provides a locus of indirection where additional leverage can be hosted.

Memento

The Memento Pattern can be used when you need to restore an object back to its previous state (undo or rollback operations).

The client requests a Memento from the source object when it needs to checkpoint the source object’s state. The source object initializes the Memento with a characterization of its state. The client is the “care-taker” of the Memento, but only the source object can store and retrieve information from the Memento (the Memento is “opaque” to the client and all other objects). If the client subsequently needs to “rollback” the source object’s state, it hands the Memento back to the source object for reinstatement.

An unlimited undo and redo capability can be readily implemented with a stack of Command objects and a stack of Memento objects.

Observer

The Observer Pattern can be used when a large monolithic design does not scale well as new graphing or monitoring requirements are requested.

Define an object that is the “keeper” of the data model and/or business logic (the Subject). Delegate all “view” functionality to decoupled and distinct Observer objects. Observers register themselves with the Subject as they are created. Whenever the Subject changes, it broadcasts to all registered Observers that it has changed, and each Observer queries the Subject for that subset of the Subject’s state that it is responsible for monitoring.

This allows the number and “type” of “view” objects to be configured dynamically, instead of being statically specified at compile-time.

Further reading

Related posts:

  1. Software design patterns (III): structural patterns
  2. Software design patterns (I)
  3. Software design patterns (II): creational patterns