Behavioral Patterns

Behavioral patterns are those which are concerned with interactions between the objects. The interactions between the objects should be such that they are talking to each other and still are loosely coupled. The loose coupling is the key to n-tier architectures. In this, the implementation and the client should be loosely coupled in order to avoid hard-coding and dependencies.

In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.

  • Chain of responsibility
    A way of passing a request between a chain of objects
  • Command
    Encapsulate a command request as an object
  • Interpreter
    A way to include language elements in a program
  • Iterator
    Sequentially access the elements of a collection
  • Mediator
    Defines simplified communication between classes
  • Memento
    Capture and restore an object’s internal state
  • Null Object
    Designed to act as a default value of an object
  • Observer
    A way of notifying change to a number of classes
  • State
    Alter an object’s behavior when its state changes

  • Strategy
    Encapsulates an algorithm inside a class
  • Template method
    Defer the exact steps of an algorithm to a subclass
  • Visitor
    Defines a new operation to a class without change

Rules of thumb

  1. Behavioral patterns are concerned with the assignment of responsibilities between objects, or, encapsulating behavior in an object and delegating requests to it.
  2. Chain of responsibility, Command, Mediator, and Observer, address how you can decouple senders and receivers, but with different trade-offs. Chain of responsibility passes a sender request along a chain of potential receivers. Command normally specifies a sender-receiver connection with a subclass. Mediator has senders and receivers reference each other indirectly. Observer defines a very decoupled interface that allows for multiple receivers to be configured at run-time.
  3. Chain of responsibility can use Command to represent requests as objects.
  4. Chain of responsibility is often applied in conjunction with Composite. There, a component’s parent can act as its successor.
  5. Command and Memento act as magic tokens to be passed around and invoked at a later time. In Command, the token represents a request; in Memento, it represents the internal state of an object at a particular time. Polymorphism is important to Command, but not to Memento because its interface is so narrow that a memento can only be passed as a value.
  6. Command can use Memento to maintain the state required for an undo operation.
  7. MacroCommands can be implemented with Composite.
  8. A Command that must be copied before being placed on a history list acts as a Prototype.
  9. Interpreter can use State to define parsing contexts.
  10. The abstract syntax tree of Interpreter is a Composite (therefore Iterator and Visitor are also applicable).
  11. Terminal symbols within Interpreter’s abstract syntax tree can be shared with Flyweight.
  12. Iterator can traverse a Composite. Visitor can apply an operation over a Composite.
  13. Polymorphic Iterators rely on Factory Methods to instantiate the appropriate Iterator subclass.
  14. Mediator and Observer are competing patterns. The difference between them is that Observer distributes communication by introducing “observer” and “subject” objects, whereas a Mediator object encapsulates the communication between other objects. We’ve found it easier to make reusable Observers and Subjects than to make reusable Mediators.
  15. On the other hand, Mediator can leverage Observer for dynamically registering colleagues and communicating with them.
  16. Mediator is similar to Facade in that it abstracts functionality of existing classes. Mediator abstracts/centralizes arbitrary communication between colleague objects, it routinely “adds value”, and it is known/referenced by the colleague objects (i.e. it defines a multidirectional protocol). In contrast, Facade defines a simpler interface to a subsystem, it doesn’t add new functionality, and it is not known by the subsystem classes (i.e. it defines a unidirectional protocol where it makes requests of the subsystem classes but not vice versa).
  17. Memento is often used in conjunction with Iterator. An Iterator can use a Memento to capture the state of an iteration. The Iterator stores the Memento internally.
  18. State is like Strategy except in its intent.
  19. Flyweight explains when and how State objects can be shared.
  20. State objects are often Singletons.
  21. Strategy lets you change the guts of an object. Decorator lets you change the skin.
  22. Strategy is to algorithm. as Builder is to creation.
  23. Strategy has 2 different implementations, the first is similar to State. The difference is in binding times (Strategy is a bind-once pattern, whereas State is more dynamic).
  24. Strategy objects often make good Flyweights.
  25. Strategy is like Template method except in its granularity.
  26. Template method uses inheritance to vary part of an algorithm. Strategy uses delegation to vary the entire algorithm.
  27. The Visitor pattern is like a more powerful Command pattern because the visitor may initiate whatever is appropriate for the kind of object it encounters.

The behavioral patterns are:

Patterns.
1. Chain of Resposibility Pattern

The chain of responsibility pattern is based on the same principle as written above. It decouples the sender of the request to the receiver. The only link between sender and the receiver is the request which is sent. Based on the request data sent, the receiver is picked. This is called “data-driven”. In most of the behavioral patterns, the data-driven concepts are used to have a loose coupling.

The responsibility of handling the request data is given to any of the members of the “chain”. If the first link of the chain cannot handle the responsibility, it passes the request data to the next level in the chain, i.e. to the next link. For readers, familiar with concepts of Java, this is similar to what happens in an Exception Hierarchy. Suppose the code written throws an ArrayIndexOutOfBoundsException. Now, this exception is because of some bug in coding and so, it gets caught at the correct level. Suppose, we have an application specific exception in the catch block. This will not be caught by that. It will find for an Exception class and will be caught by that as both the application specific exceptions and the ArrayIndexOutOfBoundsException are sub-classes of the class Exception.

Once get caught by the exception, which is the base class, it will then not look for any other exception. This is precisely the reason why, we get an “Exception is unreachable” message when we try to add a catch block with the exception below the parent exception catch block.

So, in short, the request rises in hierarchy till some object takes responsibility to handle this request.

It’s the same mechanism used for multi-level filtration. Suppose, we have a multi level filter and gravel of different sizes and shapes. We need to filter this gravel of different sizes to approx size categories. We will put the gravel on the multi-level filtration unit, with the filter of maximum size at the top and then the sizes descending. The gravel with the maximum sizes will stay on the first one and rest will pass, again this cycle will repeat until, the finest of the gravel is filtered and is collected in the sill below the filters. Each of the filters will have the sizes of gravel which cannot pass through it. And hence, we will have approx similar sizes of gravels grouped.

2. Command Pattern

This is another of the data-driven pattern. The client invokes a particular module using a command. The client passes a request, this request gets propagated as a command. The command request maps to particular modules. According to the command, a module is invoked.

This pattern is different from the Chain of Responsibility in a way that, in the earlier one, the request passes through each of the classes before finding an object that can take the responsibility. The command pattern however finds the particular object according to the command and invokes only that one.

It’s like there is a server having a lot of services to be given, and on Demand (or on command), it caters to that service for that particular client.

A classic example of this is a restaurant. A customer goes to restaurant and orders the food according to his/her choice. The waiter/ waitress takes the order (command, in this case) and hands it to the cook in the kitchen. The cook can make several types of food and so, he/she prepares the ordered item and hands it over to the waiter/waitress who in turn serves to the customer.

3. Interpreter Pattern

Intent

  • Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
  • Map a domain to a language, the language to a grammar, and the grammar to a hierarchical object-oriented design.

Problem

A class of problems 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”.

Discussion

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.

Structure

Interpreter suggests modeling the domain with a recursive grammar. Each rule in the grammar is either a ‘composite’ (a rule that references other rules) or a terminal (a leaf node in a tree structure). Interpreter relies on the recursive traversal of the Composite pattern to interpret the ‘sentences’ it is asked to process.

Scheme of Interpreter

Example

The Intepreter pattern defines a grammatical representation for a language and an interpreter to interpret the grammar. Musicians are examples of Interpreters. The pitch of a sound and its duration can be represented in musical notation on a staff. This notation provides the language of music. Musicians playing the music from the score are able to reproduce the original pitch and duration of each sound represented.

Example of Interpreter

4. Iterator Pattern

Intent

  • Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
  • The C++ and Java standard library abstraction that makes it possible to decouple collection classes and algorithms.
  • Promote to “full object status” the traversal of a collection.
  • Polymorphic traversal

Problem

Need to “abstract” the traversal of wildly different data structures so that algorithms can be defined that are capable of interfacing with each transparently.

Discussion

“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.

The Iterator abstraction is fundamental to an emerging technology called “generic programming”. This strategy seeks to explicitly separate the notion of “algorithm” from that of “data structure”. The motivation is to: promote component-based development, boost productivity, and reduce configuration management.

As an example, if you wanted to support four data structures (array, binary tree, linked list, and hash table) and three algorithms (sort, find, and merge), a traditional approach would require four times three permutations to develop and maintain. Whereas, a generic programming approach would only require four plus three configuration items.

Structure

The Client uses the Collection class’ public interface directly. But access to the Collection’s elements is encapsulated behind the additional level of abstraction called Iterator. Each Collection derived class knows which Iterator derived class to create and return. After that, the Client relies on the interface defined in the Iterator base class.

Iterator example

Example

The Iterator provides ways to access elements of an aggregate object sequentially without exposing the underlying structure of the object. Files are aggregate objects. In office settings where access to files is made through administrative or secretarial staff, the Iterator pattern is demonstrated with the secretary acting as the Iterator. Several television comedy skits have been developed around the premise of an executive trying to understand the secretary’s filing system. To the executive, the filing system is confusing and illogical, but the secretary is able to access files quickly and efficiently.

On early television sets, a dial was used to change channels. When channel surfing, the viewer was required to move the dial through each channel position, regardless of whether or not that channel had reception. On modern television sets, a next and previous button are used. When the viewer selects the “next” button, the next tuned channel will be displayed. Consider watching television in a hotel room in a strange city. When surfing through channels, the channel number is not important, but the programming is. If the programming on one channel is not of interest, the viewer can request the next channel, without knowing its number.

Iterator example

Check list

  1. Add a create_iterator() method to the “collection” class, and grant the “iterator” class privileged access.
  2. Design an “iterator” class that can encapsulate traversal of the “collection” class.
  3. Clients ask the collection object to create an iterator object.
  4. Clients use the first(), is_done(), next(), and current_item() protocol to access the elements of the collection class.

Rules of thumb

  • The abstract syntax tree of Interpreter is a Composite (therefore Iterator and Visitor are also applicable).
  • Iterator can traverse a Composite. Visitor can apply an operation over a Composite.
  • Polymorphic Iterators rely on Factory Methods to instantiate the appropriate Iterator subclass.
  • Memento is often used in conjunction with Iterator. An Iterator can use a Memento to capture the state of an iteration. The Iterator stores the Memento internally.

5. Mediator Pattern

Intent

  • 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.
  • Design an intermediary to decouple many peers.
  • Promote the many-to-many relationships between interacting peers to “full object status”.

Problem

We want to design reusable components, but dependencies between the potentially reusable pieces demonstrates the “spaghetti code” phenomenon (trying to scoop a single serving results in an “all or nothing clump”).

Discussion

In Unix, permission to access system resources is managed at three levels of granularity: world, group, and owner. A group is a collection of users intended to model some functional affiliation. Each user on the system can be a member of one or more groups, and each group can have zero or more users assigned to it. Next figure shows three users that are assigned to all three groups.

Mediator example

If we were to model this in software, we could decide to have User objects coupled to Group objects, and Group objects coupled to User objects. Then when changes occur, both classes and all their instances would be affected.

An alternate approach would be to introduce “an additional level of indirection” – take the mapping of users to groups and groups to users, and make it an abstraction unto itself. This offers several advantages: Users and Groups are decoupled from one another, many mappings can easily be maintained and manipulated simultaneously, and the mapping abstraction can be extended in the future by defining derived classes.

Mediator example

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.

The Mediator pattern promotes a “many-to-many relationship network” to “full object status”. Modelling the inter-relationships with an object enhances encapsulation, and allows the behavior of those inter-relationships to be modified or extended through subclassing.

An example where Mediator is useful is the design of a user and group capability in an operating system. A group can have zero or more users, and, a user can be a member of zero or more groups. The Mediator pattern provides a flexible and non-invasive way to associate and manage users and groups.

Structure

Mediator scheme

09

Colleagues (or peers) are not coupled to one another. Each 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.

Mediator scheme

Example

The Mediator defines an object that controls how a set of objects interact. Loose coupling between colleague objects is achieved by having colleagues communicate with the Mediator, rather than with each other. The control tower at a controlled airport demonstrates this pattern very well. The pilots of the planes approaching or departing the terminal area communicate with the tower rather than explicitly communicating with one another. The constraints on who can take off or land are enforced by the tower. It is important to note that the tower does not control the whole flight. It exists only to enforce constraints in the terminal area.

Mediator example

Check list

  1. Identify a collection of interacting objects that would benefit from mutual decoupling.
  2. Encapsulate those interactions in the abstraction of a new class.
  3. Create an instance of that new class and rework all “peer” objects to interact with the Mediator only.
  4. Balance the principle of decoupling with the principle of distributing responsibility evenly.
  5. Be careful not to create a “controller” or “god” object.

Rules of thumb

  • Chain of Responsibility, Command, Mediator, and Observer, address how you can decouple senders and receivers, but with different trade-offs. Chain of Responsibility passes a sender request along a chain of potential receivers. Command normally specifies a sender-receiver connection with a subclass. Mediator has senders and receivers reference each other indirectly. Observer defines a very decoupled interface that allows for multiple receivers to be configured at run-time.
  • Mediator and Observer are competing patterns. The difference between them is that Observer distributes communication by introducing “observer” and “subject” objects, whereas a Mediator object encapsulates the communication between other objects. We’ve found it easier to make reusable Observers and Subjects than to make reusable Mediators.
  • On the other hand, Mediator can leverage Observer for dynamically registering colleagues and communicating with them.
  • Mediator is similar to Facade in that it abstracts functionality of existing classes. Mediator abstracts/centralizes arbitrary communication between colleague objects, it routinely “adds value”, and it is known/referenced by the colleague objects (i.e. it defines a multidirectional protocol). In contrast, Facade defines a simpler interface to a subsystem, it doesn’t add new functionality, and it is not known by the subsystem classes (i.e. it defines a unidirectional protocol where it makes requests of the subsystem classes but not vice versa).

6. Momento Pattern

Intent

  • Without violating encapsulation, capture and externalize an object’s internal state so that the object can be returned to this state later.
  • A magic cookie that encapsulates a “check point” capability.
  • Promote undo or rollback to full object status.

Problem

Need to restore an object back to its previous state (e.g. “undo” or “rollback” operations).

Discussion

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.

The Memento design pattern defines three distinct roles:

  1. Originator – the object that knows how to save itself.
  2. Caretaker – the object that knows why and when the Originator needs to save and restore itself.
  3. Memento – the lock box that is written and read by the Originator, and shepherded by the Caretaker.

Structure

Memento scheme

Example

The Memento captures and externalizes an object’s internal state so that the object can later be restored to that state. This pattern is common among do-it-yourself mechanics repairing drum brakes on their cars. The drums are removed from both sides, exposing both the right and left brakes. Only one side is disassembled and the other serves as a Memento of how the brake parts fit together. Only after the job has been completed on one side is the other side disassembled. When the second side is disassembled, the first side acts as the Memento.

Memento example

Check list

  1. Identify the roles of “caretaker” and “originator”.
  2. Create a Memento class and declare the originator a friend.
  3. Caretaker knows when to “check point” the originator.
  4. Originator creates a Memento and copies its state to that Memento.
  5. Caretaker holds on to (but cannot peek into) the Memento.
  6. Caretaker knows when to “roll back” the originator.
  7. Originator reinstates itself using the saved state in the Memento.

Rules of thumb

  • Command and Memento act as magic tokens to be passed around and invoked at a later time. In Command, the token represents a request; in Memento, it represents the internal state of an object at a particular time. Polymorphism is important to Command, but not to Memento because its interface is so narrow that a memento can only be passed as a value.
  • Command can use Memento to maintain the state required for an undo operation.
  • Memento is often used in conjunction with Iterator. An Iterator can use a Memento to capture the state of an iteration. The Iterator stores the Memento internally.

7. Observer Pattern

Intent

  • Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
  • Encapsulate the core (or common or engine) components in a Subject abstraction, and the variable (or optional or user interface) components in an Observer hierarchy.
  • The “View” part of Model-View-Controller.

Problem

A large monolithic design does not scale well as new graphing or monitoring requirements are levied.

Discussion

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.

The protocol described above specifies a “pull” interaction model. Instead of the Subject “pushing” what has changed to all Observers, each Observer is responsible for “pulling” its particular “window of interest” from the Subject. The “push” model compromises reuse, while the “pull” model is less efficient.

Issues that are discussed, but left to the discretion of the designer, include: implementing event compression (only sending a single change broadcast after a series of consecutive changes has occurred), having a single Observer monitoring multiple Subjects, and ensuring that a Subject notify its Observers when it is about to go away.

The Observer pattern captures the lion’s share of the Model-View-Controller architecture that has been a part of the Smalltalk community for years.

Structure

Observer scheme

Subject represents the core (or independent or common or engine) abstraction. Observer represents the variable (or dependent or optional or user interface) abstraction. The Subject prompts the Observer objects to do their thing. Each Observer can call back to the Subject as needed.

Example

The Observer defines a one-to-many relationship so that when one object changes state, the others are notified and updated automatically. Some auctions demonstrate this pattern. Each bidder possesses a numbered paddle that is used to indicate a bid. The auctioneer starts the bidding, and “observes” when a paddle is raised to accept the bid. The acceptance of the bid changes the bid price which is broadcast to all of the bidders in the form of a new bid.

Observer example

Check list

  1. Differentiate between the core (or independent) functionality and the optional (or dependent) functionality.
  2. Model the independent functionality with a “subject” abstraction.
  3. Model the dependent functionality with an “observer” hierarchy.
  4. The Subject is coupled only to the Observer base class.
  5. The client configures the number and type of Observers.
  6. Observers register themselves with the Subject.
  7. The Subject broadcasts events to all registered Observers.
  8. The Subject may “push” information at the Observers, or, the Observers may “pull” the information they need from the Subject.

Rules of thumb

  • Chain of Responsibility, Command, Mediator, and Observer, address how you can decouple senders and receivers, but with different trade-offs. Chain of Responsibility passes a sender request along a chain of potential receivers. Command normally specifies a sender-receiver connection with a subclass. Mediator has senders and receivers reference each other indirectly. Observer defines a very decoupled interface that allows for multiple receivers to be configured at run-time.
  • Mediator and Observer are competing patterns. The difference between them is that Observer distributes communication by introducing “observer” and “subject” objects, whereas a Mediator object encapsulates the communication between other objects. We’ve found it easier to make reusable Observers and Subjects than to make reusable Mediators.
  • On the other hand, Mediator can leverage Observer for dynamically registering colleagues and communicating with them.

8. State Pattern

Intent

  • Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
  • An object-oriented state machine
  • wrapper + polymorphic wrappee + collaboration

Problem

A monolithic object’s behavior is a function of its state, and it must change its behavior at run-time depending on that state. Or, an application is characterixed by large and numerous case statements that vector flow of control based on the state of the application.

Discussion

The State pattern is a solution to the problem of how to make behavior depend on state.

  • Define a “context” class to present a single interface to the outside world.
  • Define a State abstract base class.
  • Represent the different “states” of the state machine as derived classes of the State base class.
  • Define state-specific behavior in the appropriate State derived classes.
  • Maintain a pointer to the current “state” in the “context” class.
  • To change the state of the state machine, change the current “state” pointer.

The State pattern does not specify where the state transitions will be defined. The choices are two: the “context” object, or each individual State derived class. The advantage of the latter option is ease of adding new State derived classes. The disadvantage is each State derived class has knowledge of (coupling to) its siblings, which introduces dependencies between subclasses.

A table-driven approach to designing finite state machines does a good job of specifying state transitions, but it is difficult to add actions to accompany the state transitions. The pattern-based approach uses code (instead of data structures) to specify state transitions, but it does a good job of accomodating state transition actions.

Structure

The state machine’s interface is encapsulated in the “wrapper” class. The wrappee hierarchy’s interface mirrors the wrapper’s interface with the exception of one additional parameter. The extra parameter allows wrappee derived classes to call back to the wrapper class as necessary. Complexity that would otherwise drag down the wrapper class is neatly compartmented and encapsulated in a polymorphic hierarchy to which the wrapper object delegates.

State scheme

Example

The State pattern allows an object to change its behavior when its internal state changes. This pattern can be observed in a vending machine. Vending machines have states based on the inventory, amount of currency deposited, the ability to make change, the item selected, etc. When currency is deposited and a selection is made, a vending machine will either deliver a product and no change, deliver a product and change, deliver no product due to insufficient currency on deposit, or deliver no product due to inventory depletion.

State example

Check list

  1. Identify an existing class, or create a new class, that will serve as the “state machine” from the client’s perspective. That class is the “wrapper” class.
  2. Create a State base class that replicates the methods of the state machine interface. Each method takes one additional parameter: an instance of the wrapper class. The State base class specifies any useful “default” behavior.
  3. Create a State derived class for each domain state. These derived classes only override the methods they need to override.
  4. The wrapper class maintains a “current” State object.
  5. All client requests to the wrapper class are simply delegated to the current State object, and the wrapper object’s this pointer is passed.
  6. The State methods change the “current” state in the wrapper object as appropriate.

Rules of thumb

  • State objects are often Singletons.
  • Flyweight explains when and how State objects can be shared.
  • Interpreter can use State to define parsing contexts.
  • Strategy has 2 different implementations, the first is similar to State. The difference is in binding times (Strategy is a bind-once pattern, whereas State is more dynamic).
  • The structure of State and Bridge are identical (except that Bridge admits hierarchies of envelope classes, whereas State allows only one). The two patterns use the same structure to solve different problems: State allows an object’s behavior to change along with its state, while Bridge’s intent is to decouple an abstraction from its implementation so that the two can vary independently.
  • The implementation of the State pattern builds on the Strategy pattern. The difference between State and Strategy is in the intent. With Strategy, the choice of algorithm is fairly stable. With State, a change in the state of the “context” object causes it to select from its “palette” of Strategy objects.

9. Strategy Pattern

Intent

  • Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.
  • Capture the abstraction in an interface, bury implementation details in derived classes.

Problem

One of the dominant strategies of object-oriented design is the “open-closed principle”.

Figure demonstrates how this is routinely achieved – encapsulate interface details in a base class, and bury implementation details in derived classes. Clients can then couple themselves to an interface, and not have to experience the upheaval associated with change: no impact when the number of derived classes changes, and no impact when the implementation of a derived class changes.

Strategy scheme

A generic value of the software community for years has been, “maximize cohesion and minimize coupling”. The object-oriented design approach shown in figure is all about minimizing coupling. Since the client is coupled only to an abstraction (i.e. a useful fiction), and not a particular realization of that abstraction, the client could be said to be practicing “abstract coupling” . an object-oriented variant of the more generic exhortation “minimize coupling”.

A more popular characterization of this “abstract coupling” principle is “Program to an interface, not an implementation”.

Clients should prefer the “additional level of indirection” that an interface (or an abstract base class) affords. The interface captures the abstraction (i.e. the “useful fiction”) the client wants to exercise, and the implementations of that interface are effectively hidden.

Structure

The Interface entity could represent either an abstract base class, or the method signature expectations by the client. In the former case, the inheritance hierarchy represents dynamic polymorphism. In the latter case, the Interface entity represents template code in the client and the inheritance hierarchy represents static polymorphism.

Strategy scheme

Example

A Strategy defines a set of algorithms that can be used interchangeably. Modes of transportation to an airport is an example of a Strategy. Several options exist such as driving one’s own car, taking a taxi, an airport shuttle, a city bus, or a limousine service. For some airports, subways and helicopters are also available as a mode of transportation to the airport. Any of these modes of transportation will get a traveler to the airport, and they can be used interchangeably. The traveler must chose the Strategy based on tradeoffs between cost, convenience, and time.

Strategy example

Check list

  1. Identify an algorithm (i.e. a behavior) that the client would prefer to access through a “flex point”.
  2. Specify the signature for that algorithm in an interface.
  3. Bury the alternative implementation details in derived classes.
  4. Clients of the algorithm couple themselves to the interface.

Rules of thumb

  • Strategy is like Template Method except in its granularity.
  • State is like Strategy except in its intent.
  • Strategy lets you change the guts of an object. Decorator lets you change the skin.
  • State, Strategy, Bridge (and to some degree Adapter) have similar solution structures. They all share elements of the ‘handle/body’ idiom. They differ in intent – that is, they solve different problems.
  • Strategy has 2 different implementations, the first is similar to State. The difference is in binding times (Strategy is a bind-once pattern, whereas State is more dynamic).
  • Strategy objects often make good Flyweights.

10. Template Pattern

Intent

  • Define the skeleton of an algorithm in an operation, deferring some steps to client subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
  • Base class declares algorithm ‘placeholders’, and derived classes implement the placeholders.

Problem

Two different components have significant similarities, but demonstrate no reuse of common interface or implementation. If a change common to both components becomes necessary, duplicate effort must be expended.

Discussion

The component designer decides which steps of an algorithm are invariant (or standard), and which are variant (or customizable). The invariant steps are implemented in an abstract base class, while the variant steps are either given a default implementation, or no implementation at all. The variant steps represent “hooks”, or “placeholders”, that can, or must, be supplied by the component’s client in a concrete derived class.

The component designer mandates the required steps of an algorithm, and the ordering of the steps, but allows the component client to extend or replace some number of these steps.

Template Method is used prominently in frameworks. Each framework implements the invariant pieces of a domain’s architecture, and defines “placeholders” for all necessary or interesting client customization options. In so doing, the framework becomes the “center of the universe”, and the client customizations are simply “the third rock from the sun”. This inverted control structure has been affectionately labelled “the Hollywood principle” – “don’t call us, we’ll call you”.

Structure

Template Method scheme

The implementation of template_method() is: call step_one(), call step_two(), and call step_three(). step_two() is a “hook” method – a placeholder. It is declared in the base class, and then defined in derived classes. Frameworks (large scale reuse infrastructures) use Template Method a lot. All reusable code is defined in the framework’s base classes, and then clients of the framework are free to define customizations by creating derived classes as needed.

Template Method scheme

Example

The Template Method defines a skeleton of an algorithm in an operation, and defers some steps to subclasses. Home builders use the Template Method when developing a new subdivision. A typical subdivision consists of a limited number of floor plans with different variations available for each. Within a floor plan, the foundation, framing, plumbing, and wiring will be identical for each house. Variation is introduced in the later stages of construction to produce a wider variety of models.

Template Method example

Check list

  1. Examine the algorithm, and decide which steps are standard and which steps are peculiar to each of the current classes.
  2. Define a new abstract base class to host the “don’t call us, we’ll call you” framework.
  3. Move the shell of the algorithm (now called the “template method”) and the definition of all standard steps to the new base class.
  4. Define a placeholder or “hook” method in the base class for each step that requires many different implementations. This method can host a default implementation – or – it can be defined as abstract (Java) or pure virtual (C++).
  5. Invoke the hook method(s) from the template method.
  6. Each of the existing classes declares an “is-a” relationship to the new abstract base class.
  7. Remove from the existing classes all the implementation details that have been moved to the base class.
  8. The only details that will remain in the existing classes will be the implementation details peculiar to each derived class.

Rules of thumb

  • Strategy is like Template Method except in its granularity.
  • Template Method uses inheritance to vary part of an algorithm. Strategy uses delegation to vary the entire algorithm.
  • Strategy modifies the logic of individual objects. Template Method modifies the logic of an entire class.
  • Factory Method is a specialization of Template Method.

11. Visitor Pattern

Intent

  • 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.
  • The classic technique for recovering lost type information.
  • Do the right thing based on the type of two objects.
  • Double dispatch

Problem

Many distinct and unrelated operations need to be performed on node objects in a heterogeneous aggregate structure. You want to avoid “polluting” the node classes with these operations. And, you don’t want to have to query the type of each node and cast the pointer to the correct type before performing the desired operation.

Discussion

Visitor’s primary purpose is to abstract functionality that can be applied to an aggregate hierarchy of “element” objects. The approach encourages designing lightweight Element classes – because processing functionality is removed from their list of responsibilities. New functionality can easily be added to the original inheritance hierarchy by creating a new Visitor subclass.

Visitor implements “double dispatch”. OO messages routinely manifest “single dispatch” – the operation that is executed depends on: the name of the request, and the type of the receiver. In “double dispatch”, the operation executed depends on: the name of the request, and the type of TWO receivers (the type of the Visitor and the type of the element it visits).

The implementation proceeds as follows. Create a Visitor class hierarchy that defines a pure virtual visit() method in the abstract base class for each concrete derived class in the aggregate node hierarchy. Each visit() method accepts a single argument – a pointer or reference to an original Element derived class.

Each operation to be supported is modelled with a concrete derived class of the Visitor hierarchy. The visit() methods declared in the Visitor base class are now defined in each derived subclass by allocating the “type query and cast” code in the original implementation to the appropriate overloaded visit() method.

07

Add a single pure virtual accept() method to the base class of the Element hierarchy. accept() is defined to receive a single argument – a pointer or reference to the abstract base class of the Visitor hierarchy.

Each concrete derived class of the Element hierarchy implements the accept() method by simply calling the visit() method on the concrete derived instance of the Visitor hierarchy that it was passed, passing its this” pointer as the sole argument.

Everything for “elements” and “visitors” is now set-up. When the client needs an operation to be performed, (s)he creates an instance of the Vistor object, calls the accept() method on each Element object, and passes the Visitor object.

The accept() method causes flow of control to find the correct Element subclass. Then when the visit() method is invoked, flow of control is vectored to the correct Visitor subclass. accept() dispatch plus visit() dispatch equals double dispatch.

11

The Visitor pattern makes adding new operations (or utilities) easy – simply add a new Visitor derived class. But, if the subclasses in the aggregate node hierarchy are not stable, keeping the Visitor subclasses in sync requires a prohibitive amount of effort.

12

An acknowledged objection to the Visitor pattern is that is represents a regression to functional decomposition – separate the algorithms from the data structures. While this is a legitimate interpretation, perhaps a better perspective/rationale is the goal of promoting non-traditional behavior to full object status.

Structure

13

The Element hierarchy is instrumented with a “universal method adapter”. The implementation of accept() in each Element derived class is always the same. But – it cannot be moved to the Element base class and inherited by all derived classes because a reference to this in the Element class always maps to the base type Element.

Visitor scheme

14

When the polymorphic firstDispatch() method is called on an abstract First object, the concrete type of that object is “recovered”. When the polymorphic secondDispatch() method is called on an abstract Second object, its concrete type is “recovered”. The application functionality appropriate for this pair of types can now be exercised.

Visitor scheme

Example

15

The Visitor pattern represents an operation to be performed on the elements of an object structure without changing the classes on which it operates. This pattern can be observed in the operation of a taxi company. When a person calls a taxi company (accepting a visitor), the company dispatches a cab to the customer. Upon entering the taxi the customer, or Visitor, is no longer in control of his or her own transportation, the taxi (driver) is.

Visitor example

Check list

16

  1. Confirm that the current hierarchy (known as the Element hierarchy) will be fairly stable and that the public interface of these classes is sufficient for the access the Visitor classes will require. If these conditions are not met, then the Visitor pattern is not a good match.
  2. Create a Visitor base class with a visit(ElementXxx) method for each Element derived type.
  3. Add an accept(Visitor) method to the Element hierarchy. The implementation in each Element derived class is always the same – accept( Visitor v ) { v.visit( this ); }. Because of cyclic dependencies, the declaration of the Element and Visitor classes will need to be interleaved.
  4. The Element hierarchy is coupled only to the Visitor base class, but the Visitor hierarchy is coupled to each Element derived class. If the stability of the Element hierarchy is low, and the stability of the Visitor hierarchy is high; consider swapping the ‘roles’ of the two hierarchies.
  5. Create a Visitor derived class for each “operation” to be performed on Element objects. visit() implementations will rely on the Element’s public interface.
  6. The client creates Visitor objects and passes each to Element objects by calling accept().

Rules of thumb

  • The abstract syntax tree of Interpreter is a Composite (therefore Iterator and Visitor are also applicable).
  • Iterator can traverse a Composite. Visitor can apply an operation over a Composite.
  • The Visitor pattern is like a more powerful Command pattern because the visitor may initiate whatever is appropriate for the kind of object it encounters.
  • The Visitor pattern is the classic technique for recovering lost type information without resorting to dynamic casts.

Notes

The November 2000 issue of JavaPro has an article by James Cooper (author of a Java companion to the GoF) on the Visitor design pattern. He suggests it “turns the tables on our object-oriented model and creates an external class to act on data in other classes … while this may seem unclean … there are good reasons for doing it.”

His primary example. Suppose you have a hierarchy of Employee-Engineer-Boss. They all enjoy a normal vacation day accrual policy, but, Bosses also participate in a “bonus” vacation day program. As a result, the interface of class Boss is different than that of class Engineer. We cannot polymorphically traverse a Composite-like organization and compute a total of the organization’s remaining vacation days. “The Visitor becomes more useful when there are several classes with different interfaces and we want to encapsulate how we get data from these classes.”

His benefits for Visitor include:

  • Add functions to class libraries for which you either do not have the source or cannot change the source
  • Obtain data from a disparate collection of unrelated classes and use it to present the results of a global calculation to the user program
  • Gather related operations into a single class rather than force you to change or derive classes to add these operations
  • Collaborate with the Composite pattern

Visitor is not good for the situation where “visited” classes are not stable. Every time a new Composite hierarchy derived class is added, every Visitor derived class must be amended.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s