Download as pdf or txt
Download as pdf or txt
You are on page 1of 12

1

6. Structural and Behavioral Design Patterns


Structural
These design patterns are about organizing different classes and objects to form larger
structures and provide new functionality.
Structural design patterns are Adapter, Bridge, Composite, Decorator, Facade, Flyweight,
Private Class Data, and Proxy.
Use Case Of Structural Design Pattern-
1) When 2 interfaces are not compatible with each other and want to establish a relationship
between them through an adapter it's called adapter design pattern.
2) Adapter pattern converts the interface of a class into another interface or classes the client
expects that is adapter lets classes works together that could not otherwise because of
incompatibility. so in these types of incompatible scenarios, we can go for the adapter pattern.

Adapter [Wrapper]
Intent
● Convert the interface of a class into another interface clients expect. Adapter lets
classes work together that couldn't otherwise because of incompatible interfaces.
● Wrap an existing class with a new interface.
● Impedance match an old component to a new system

Applicability
Use the Adapter pattern when
● you want to use an existing class, and its interface does not match the one you need.
● you want to create a reusable class that cooperates with unrelated or unforeseen
classes, that is, classes that don't necessarily have compatible interfaces.
● (object adapter only) you need to use several existing subclasses, but it's impractical
to adapt their interface by subclassing every one. An object adapter can adapt the
interface of its parent class.
Structure
A class adapter uses multiple inheritance to adapt one interface to another:

An object adapter relies on object composition:

By Omkar Javadwar
2

Collaborations
● Clients call operations on an Adapter instance. In turn, the adapter calls Adaptee
operations that carry out the request.

The classes/objects participating in adapter pattern:


● Target - defines the domain-specific interface that Client uses.
● Adapter - adapts the interface Adaptee to the Target interface.
● Adaptee - defines an existing interface that needs adapting.
● Client - collaborates with objects conforming to the Target interface.

Consequences
Class and object adapters have different trade-offs. A class adapter
● adapts Adaptee to Target by committing to a concrete Adapter class. As a
consequence, a class adapter won't work when we want to adapt a class and all its
subclasses.
● lets Adapter override some of Adaptee's behavior, since Adapter is a subclass of
Adaptee.
● introduces only one object, and no additional pointer indirection is needed to get to
the adaptee.
An object adapter
● lets a single Adapter work with many Adaptees—that is, the Adaptee itself and all of
its subclasses (if any). The Adapter can also add functionality to all Adaptees at once.
● makes it harder to override Adaptee behavior. It will require subclassing Adaptee and
making Adapter refer to the subclass rather than the Adaptee itself.

How Much the Adapter Should Do?


This question has a really simple response: it should do how much it has to in order to adapt.
It's very simple, if the Target and Adaptee are similar then the adapter has just to delegate the
requests from the Target to the Adaptee. If Target and Adaptee are not similar, then the
adapter might have to convert the data structures between those and to implement the
operations required by the Target but not implemented by the Adaptee.

By Omkar Javadwar
3

Two-Ways Adapters
The Two-Ways Adapters are adapters that implements both interfaces of Target and Adaptee.
The adapted object can be used as Target in new systems dealing with Target classes or as
Adaptee in other systems dealing with Adaptee classes. Going further on this line of thinking,
we can have adapters implementing n interfaces, adapting to n systems. Two-way adapters
and n-way adapters are hard to implement in systems not supporting multiple inheritance. If
adapter has to extend the Target class it can not extent another class like Adaptee, so the
Adaptee should be an interface and all the calls should be delegated from the adapter to the
Adaptee object.

Adapter Pattern and Strategy Pattern


Adapter Pattern and Strategy Pattern - there are many cases when the adapter can play the
role of the Strategy Pattern. If we have several modules implementing the same functionality
and we wrote adapters for them, the adapters are implementing the same interface. We can
simply replace the adapters objects at run time because they implements the same interface.

Implementation
Although the implementation of Adapter is usually straightforward, here are some issues to
keep in mind:
1. Implementing class adapters in C++. In a C++ implementation of a class adapter, Adapter
would inherit publicly from Target and privately from Adaptee. Thus Adapter would be a
subtype of Target but not of Adaptee.
2. Pluggable adapters. Let's look at three ways to implement pluggable adapters for the
TreeDisplay widget described earlier, which can lay out and display a hierarchical structure
automatically.

Bridge[Handle/Body]
Intent
● Decouple an abstraction from its implementation so that the two can vary
independently.
● Publish interface in an inheritance hierarchy, and bury implementation in its own
inheritance hierarchy.
● Beyond encapsulation, to insulation

Applicability
The bridge pattern applies when there is a need to avoid permanent binding between an
abstraction and an implementation and when the abstraction and implementation need to vary
independently. Using the bridge pattern would leave the client code unchanged with no need
to recompile the code.

Structure

By Omkar Javadwar
4

The participants classes in the bridge pattern are:


● Abstraction - Abstraction defines abstraction interface.
● AbstractionImpl - Implements the abstraction interface using a reference to an object
of type Implementor.
● Implementor - Implementor defines the interface for implementation classes. This
interface does not need to correspond directly to abstraction interface and can be very
different. Abstraction imp provides an implementation in terms of operations provided
by Implementor interface.
● ConcreteImplementor1, ConcreteImplementor2 - Implements the Implementor
interface.

Collaborations
● Abstraction forwards client requests to its Implementor object.

Consequences
Known Uses:
● Decoupling interface and implementation. An implementation is not bound
permanently to an interface. The implementation of an abstraction can be configured
and even switched at run-time.
● Abstraction and Implementor hierarchies can be extended independently.

Implementation
● Only one Implementor. In situations where there's only one implementation, creating
an abstract Implementor class isn't necessary.
● Creating the right Implementor object. How, when, and where do you decide which
Implementor class to instantiate when there's more than one?
● Sharing implementors. Coplien illustrates how the Handle/Body idiom in C++ can be
used to share implementations among several objects [Cop92]. The Body stores a
reference count that the Handle class increments and decrements.

By Omkar Javadwar
5

Composite
Intent
● Compose objects into tree structures to represent whole-part hierarchies. Composite
lets clients treat individual objects and compositions of objects uniformly.
● Recursive composition
● "Directories contain entries, each of which could be a directory."
● 1-to-many "has a" up the "is a" hierarchy

Applicability
The composite pattern applies when there is a part-whole hierarchy of objects and a client
needs to deal with objects uniformly regardless of the fact that an object might be a leaf or a
branch.
Structure

Participants
● Component - Component is the abstraction for leafs and composites. It defines the
interface that must be implemented by the objects in the composition. For example a
file system resource defines move, copy, rename, and getSize methods for files and
folders.
● Leaf - Leafs are objects that have no children. They implement services described by
the Component interface. For example a file object implements move, copy, rename,
as well as getSize methods which are related to the Component interface.
● Composite - A Composite stores child components in addition to implementing
methods defined by the component interface. Composites implement methods defined
in the Component interface by delegating to child components. In addition composites
provide additional methods for adding, removing, as well as getting components.
● Client - The client manipulates objects in the hierarchy using the component interface.

Collaborations
● Clients use the Component class interface to interact with objects in the composite
structure. If the recipient is a Leaf, then the request is handled directly. If the recipient

By Omkar Javadwar
6

is a Composite, then it usually forwards requests to its child components, possibly


performing additional operations before and/or after forwarding.

Consequences
● The composite pattern defines class hierarchies consisting of primitive objects and
composite objects. Primitive objects can be composed into more complex objects,
which in turn can be composed.
● Clients treat primitive and composite objects uniformly through a component
interface which makes client code simple.
● Adding new components can be easy and client code does not need to be changed
since client deals with the new components through the component interface.

Implementation
1. Explicit parent references.Maintaining references from child components to their
parent can simplify the traversal and management of a composite structure.
2. Sharing components. It's often useful to share components, for example, to reduce
storage requirements. But when a component can have no more than one parent,
sharing components becomes difficult.
3. Maximizing the Component interface. One of the goals of the Composite pattern is to
make clients unaware of the specific Leaf or Composite classes they're using. To
attain this goal, the Component class should define as many common operations for
Composite and Leaf classes as possible.
4. Declaring the child management operations. Although the Composite class
implements the Add and Remove operations for managing children, an important
issue in the Composite pattern is which classes declare these operations in the
Composite class hierarchy.

Behavioral
Behavioral patterns are about identifying common communication patterns between objects
and realize these patterns.
Behavioral patterns are Chain of responsibility, Command, Interpreter, Iterator, Mediator,
Memento, Null Object, Observer, State, Strategy, Template method, Visitor
Use Case of Behavioral Design Pattern-
Template pattern defines the skeleton of an algorithm in an operation, deferring some steps to
sub-classes, Template method lets subclasses redefine certain steps of an algorithm without
changing the algorithm structure. say for an example in your project you want the behavior of
the module can be extended, such that we can make the module behave in new and different
ways as the requirements of the application change, or to meet the needs of new applications.
However, No one is allowed to make source code changes to it. it means you can add but
can’t modify the structure in those scenarios a developer can approach template design
pattern.

By Omkar Javadwar
7

Chain of Responsibility
Intent
● Avoid coupling the sender of a request to its receiver by giving more than one object a
chance to handle the request. Chain the receiving objects and pass the request along
the chain until an object handles it.
● Launch-and-leave requests with a single processing pipeline that contains many
possible handlers.
● An object-oriented linked list with recursive traversal.

Applicability
Having so many design patterns to choose from when writing an application, it's hard to
decide on which one to use, so here are a few situations when using the Chain of
Responsibility is more effective:
● More than one object can handle a command
● The handler is not known in advance
● The handler should be determined automatically
● It’s wished that the request is addressed to a group of objects without explicitly
specifying its receiver
● The group of objects that may handle the command must be specified in a dynamic
way

Structure

A typical object structure might look like this:

Participants
● Handler - defines an interface for handling requests
● RequestHandler - handles the requests it is responsible for

By Omkar Javadwar
8

● If it can handle the request it does so, otherwise it sends the request to its successor
● Client - sends commands to the first object in the chain that may handle the command

Collaborations
● When a client issues a request, the request propagates along the chain until a
ConcreteHandler object takes responsibility for handling it.

Consequences
Chain of Responsibility has the following benefits and liabilities:
1. Reduced coupling.The pattern frees an object from knowing which other object
handles a request. An object only has to know that a request will be
handled"appropriately." Both the receiver and the sender have no explicit knowledge
of each other, and an object in the chain doesn't have to know about the chain's
structure.
2. Added flexibility in assigning responsibilities to objects.Chain of Responsibility gives
you added flexibility in distributing responsibilities among objects.
3. Receipt isn't guaranteed.Since a request has no explicit receiver, there's no guarantee
it'll be handled—the request can fall off the end of the chain without ever being
handled. A request can also go unhandled when the chain is not configured properly.

Implementation
1. Implementing the successor chain.There are two possible ways to implement the
successor chain:
a. Define new links (usually in the Handler, but Concrete Handlers could define them
instead).
b. Use existing links.
2. Connecting successors.If there are no pre existing references for defining a chain, then
you'll have to introduce them yourself.
3. Representing requests.Different options are available for representing requests. In the
simplest form, the request is a hard-coded operation invocation, as in the case of
HandleHelp. This is convenient and safe, but you can forward only the fixed set of
requests that the Handler class defines.
4. Automatic forwarding in Smalltalk.You can use the does Not Understand mechanism
in Smalltalk to forward requests.

Command [Action, Transaction]


Intent
● Encapsulates a request as an object, thereby letting you parametrize clients with
different requests, queue or log requests, and support undoable operations.
● Promote "invocation of a method on an object" to full object status
● An object-oriented callback

By Omkar Javadwar
9

Applicability
The applicability of the Command design pattern can be found in these cases below:
● parameterized objects depending on the action they must perform
● specifies or adds in a queue and executes requests at different moments in time
● offers support for undoable actions (the Execute method can memorize the state and
allow going back to that state)
● structures the system in high level operations that based on primitive operations
● decouples the object that invokes the action from the object that performs the action.
Due to this usage it is also known as Producer - Consumer design pattern.

Structure

The classes participating in the pattern are:


● Command - declares an interface for executing an operation;
● ConcreteCommand - extends the Command interface, implementing the Execute
method by invoking the corresponding operations on Receiver. It defines a link
between the Receiver and the action.
● Client - creates a ConcreteCommand object and sets its receiver;
● Invoker - asks the command to carry out the request;
● Receiver - knows how to perform the operations.

Collaborations
● The client creates a ConcreteCommand object and specifies its receiver.
● An Invoker object stores the ConcreteCommand object.
● The invoker issues a request by calling Execute on the command. When Commands
are undoable, ConcreteCommand stores state for undoing the command prior to
invoking Execute.
● The ConcreteCommand object invokes operations on its receiver to carry out the
request.

The following diagram shows the interactions between these objects.It illustrates how
Command decouples the invoker from the receiver(and the request it carries out).

By Omkar Javadwar
10

Consequences
The Command pattern has the following consequences:
1. Command decouples the object that invokes the operation from the one that knows how to
perform it.
2. Commands are first-class objects. They can be manipulated and extended like any other
object.
3. You can assemble commands into a composite command. An example is the Macro
Command class described earlier. In general, composite commands are an instance of the
Composite pattern.
4. It's easy to add new Commands, because you don't have to change existing classes.

Implementation
1. How intelligent should a command be?A command can have a wide range of abilities.
At one extreme it merely defines a binding between a receiver and the actions that
carry out the request. At the other extreme it implements everything itself without
delegating to a receiver at all.
2. Supporting undo and redo.This state can include
● the Receiver object, which actually carries out operations in response to the request,
● the arguments to the operation performed on the receiver, and
● any original values in the receiver that can change as a result of handling the request.
The receiver must provide operations that let the command return the receiver to its
prior state.
3. Avoiding error accumulation in the undo process.
4. Using C++ templates.For commands that (1) aren't undoable and (2) don't require
arguments,we can use C++ templates to avoid creating a Command subclass for every
kind of action and receiver.

Iterator [Cursor]
Intent
● Provide a way to access the elements of an aggregate object sequentially without
exposing its underlying representation.

By Omkar Javadwar
11

● 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

Applicability
The iterator pattern allow us to:
● access the contents of a collection without exposing its internal structure.
● support multiple simultaneous traversals of a collection.
● provide a uniform interface for traversing different collection.

Structure

Participants
● Iterator :defines an interface for accessing and traversing elements.
● ConcreteIterator :implements the Iterator interface.
● Design Patterns:
1. Elements of Reusable Object-Oriented Software
2. keeps track of the current position in the traversal of the aggregate.
● Aggregate: defines an interface for creating an Iterator object.
● ConcreteAggregate: implements the Iterator creation interface to return an instance
of the proper ConcreteIterator.

Collaborations
● A ConcreteIterator keeps track of the current object in the aggregate and can compute
the succeeding object in the traversal.

Consequences
The Iterator pattern has three important consequences:

By Omkar Javadwar
12

1. It supports variations in the traversal of an aggregate.Complex aggregates may be traversed


in many ways. For example, codegeneration and semantic checking involve traversing parse
trees. Code generation may traverse the parse tree inorder or preorder.Iterators make it easy to
change the traversal algorithm: Just replace the iterator instance with a different one. You can
also defineIterator subclasses to support new traversals.
2. Iterators simplify the Aggregate interface.Iterator's traversal interface obviates the need for
a similar interface in Aggregate, thereby simplifying the aggregate's interface.
3. More than one traversal can be pending on an aggregate.An iterator keeps track of its own
traversal state. Therefore you can have more than one traversal in progress at once.

Implementation
Iterator has many implementation variants and alternatives. Some important ones follow. The
trade-offs often depend on the control structures your language provides. Some languages
(CLU [LG86], for example) even support this pattern directly.

1. Who controls the iteration?A fundamental issue is deciding which party controls the
iteration,the iterator or the client that uses the iterator. When the clientcontrols the
iteration, the iterator is called an external iterator, and when the iterator controls it, the
iterator is an internal iterator.
2. Who defines the traversal algorithm?The iterator is not the only place where the
traversal algorithm can be defined. The aggregate might define the traversal algorithm
and use the iterator to store just the state of the iteration. We call this kind of iterator a
cursor
3. How robust is the iterator?It can be dangerous to modify an aggregate while you're
traversing it.If elements are added or deleted from the aggregate, you might end up
accessing an element twice or missing it completely.
4. Additional Iterator operations.The minimal interface to Iterator consists of the
operations First,Next, IsDone, and CurrentItem. Some additional operations might
prove useful.
5. Using polymorphic iterators in C++.Polymorphic iterators have their cost. They
require the iterator object to be allocated dynamically by a factory method. Hence
they should be used only when there's a need for polymorphism. Otherwise use
concrete iterators, which can be allocated on the stack.
6. Iterators may have privileged access.An iterator can be viewed as an extension of the
aggregate that created it. The iterator and the aggregate are tightly coupled.
7. Iterators for composites.
8. Null iterators.A NullIterator is a degenerate iterator that's helpful for handling
boundary conditions. By definition, a NullIterator is always done with traversal; that
is, its IsDone operation always evaluates to true.
For more references:
https://sourcemaking.com/design_patterns
https://www.oodesign.com/

By Omkar Javadwar

You might also like