Chapter 10: Design Patterns (Behavioural)

Behavioural Patterns
• Concerned about the manner in which
objects communicate with each other.
• Deal with problems that surface during
the assignment of responsibilities to
classes and the design of algorithms.
• May use inheritance structures to spread
behaviour across the subclasses or they
may use aggregation and composition to
build complex behaviour from simpler
components.
Behavioural Patterns
•
•
•
•
•
•
•
•
•
•
•
Strategy
State
Observer
Mediator
Visitor
Chain of Responsibility
Interpreter
Memento
Template
Command
Iterator
Strategy Pattern
• A number of algorithms encapsulated within
classes.
• The client can select one out of the available
algorithms.
• E.g. Encapsulate various strategies of sorting
within the classes.
• Depending upon the selection made by the user,
the object of that particular class is instantiated
and the operation (which implements that
particular strategy) is carried out.
• The algorithms should be encapsulated within a
common method (in our case the Sort()
method) implemented by different classes.
Strategy Pattern
• Algorithm to be used can be selected by other factors such
as the efficiency of computation.
• E.g. Consider 2 algorithms BubbleSort and QuickSort.
BubbleSort works best for inputs that are in “almost sorted
order” and worst for inputs that are not in “almost sorted
order”.
• QuickSort works best for inputs which are completely
unsorted and worst for inputs which are in “almost sorted
order”.
• If an input is present which consists of numbers that are in
“almost sorted order”, then it is advisable to use the
algorithm of BubbleSort solely on the criterion of efficiency.
State Pattern
• Used when the programmer wants to switch between
classes and invoke the method of the current class in which
it is in.
• E.g. Toggling between the objects of 2 classes (Off and On)
and printing the name of the class it currently is in.
• These classes are extended from the abstract class State.
• The statename variables have the names Off and On
respectively.
• This pattern localizes state-specific behaviour in an
individual class for each state and puts the behaviour for
that state within a single object.
• The transitions from one state to another are explicit.
• If there are numerous states, a lot of objects are created.
However this leads to the simplification of the program.
State v/s Strategy Pattern
• Both have behaviour encapsulated within the method of a
class.
• In the strategy pattern, only 1 strategy is active throughout
the life of the program.
• This strategy may have been selected by the user or the
selection may have been done because of the
computational efficiency.
• In the state pattern, multiple states are active during the
life of the program.
• The object transitions to a state, executes the behaviour
present in that state, transitions to another state, executes
the behaviour present in that state and so on.
Observer Pattern
• E.g. Changing value of the stock of a Company.
• Suppose there are many shareholders who wish to be
notified at every change in price of the stock of this
company.
• The price of stock is continuously observed and if it
changes the investors are notified of the change.
• Example can be extended by adding many companies and
many investors of different companies.
• Depending upon who is a stockholder of a particular
company and the change in price of stock of that company,
the appropriate investors could be notified.
• In the actual implementation of the observer, the data is
called the “Subject” and the parties interested in the data
are called the “Observers”. In our e.g. Stock/SBW are the
Subjects and the Investor class is the Observer.
Mediator Pattern
• When a program consists of many classes, the logic of the
program is divided between them.
• If there are a large number of classes they can become
heavily coupled and the complexity of communication
between them increases.
• The program becomes harder to change because change in
one class can affect code in other classes.
• The Mediator pattern gives redressal to this problem by
promoting looser coupling between the involved classes.
• The Mediator accomplishes this by being the only class that
has the detailed knowledge of the methods in other
classes.
• Classes send information to the Mediator and the Mediator
passes this information to the other classes that need to be
informed.
Mediator Pattern
• E.g. Two colleagues talking to each other
through the mediator.
• Each Colleague sends a message to the
Mediator.
• The Mediator checks the name of the sender. If
the sender is the first Colleague, the recipient is
the second and vice versa.
• The Mediator is a special class that contains
methods for each colleague to invoke (in our
example, the Send( ) method ) and knows
about the method present in each Colleague (in
our example, the Notify( ) method ).
Visitor Pattern
• This pattern is used to fetch data across a number of
instances of one or in general of many classes.
• It can fetch data across a variety of objects whose classes
may not be related at all!!!!.
• It can then use this data for some centralized calculation.
• It is very easy to add new operations to a program using
visitors, because the visitor contains the code and not the
individual classes.
• The visitor can gather related operations into a single class
rather than compelling the change to or derivation from
each individual class.
• This can make the program simpler to write and maintain.
Class diagram of Visitor Pattern
Visitor Pattern
• E.g.Find the total days of vacation taken by its 4 employees.
• A class Employee with the attributes name and vacdays is
designed.
• Four objects are instantiated with 4 different values of vacdays.
• An object of the VacationVisitor is instantiated and passed as a
parameter to each object’s accept() method.
• Thus, the visitor is first accepted by each of these four objects.
• It then fetches information from each object and adds them up to
give the required total number of days.
Visitor Pattern
• Method is dispatched twice for the visitor to
work.
• Each employee object's accept() method is
invoked first in which the visitor is accepted and
the accept() method invokes the visitor's visit()
method.
• It is this bi-directional calling that permits the
introduction of operations on any class that has
an accept method since the visitor can then
fetch the data from each of these classes and
can carry out the necessary operations.
Visitor Pattern
• Although the visitor can be accepted from any
number of classes, it is not allowed to fetch
private data belonging to the classes.
• If the data is made public the principle of
encapsulation is violated.
• Thus, in order to provide the visitor with the
data and upholding encapsulation at the same
time a large number of public methods may
have to be written.
Visitor Pattern
• New operations can be added to the program using visitors
because the code is inside the visitor class’ method rather
than the methods of the program classes.
• In our program the visit() method of the visitor class
contains the actual code to compute the total days.
• The concept of the visitor pattern is most helpful when
most of the classes have already been developed and
addition of new classes is unlikely.
• If the visitors are used at an early stage, then, for every
new class the visitor has to visit for a specific purpose,
implementation for the visit() method has to be written
every time.
Chain of Responsibility Pattern
• There are a number of classes in a chain.
• A request is passed on to the first class.
• If this class cannot handle it, it is passed on to
the next class in the chain.
• If this class cannot handle it, the request goes
on to the next class and this process goes on till
a class which can handle the request is found.
• Each class does not know about the capability of
the other classes.
• In this pattern, there is a loose coupling
between the classes, the only common link is
the request that is passed between them.
Class Diagram of ‘Chain of
Responsibility’ Pattern
Chain of Responsibility Pattern
• Consider the company SBW in which gets requests from
different departments first come to the Company Secretary.
• If the money needed to be sanctioned is less than Rs.
1,00,000 he is authorized to handle the request.
• Else he passes the request file to the Vice President after
affixing his own initials.
• If the amount is less than Rs. 2,50,000, the Vice President
can sanction the amount else, he also affixes his initials
and passes the file to the President.
• If the amount is less than Rs. 5,00,000, the President can
sanction it else he has to call a board meeting!
Chain of Responsibility Pattern
• This pattern is used when there is more than 1 handler to
handler a request and which can be determined
automatically by the chain.
• It is very useful if the client does not know explicitly, which
object actually handles the request.
• This pattern gives the programmer flexibility to distribute
responsibilities across objects.
• The chain of responsibility is from the most specific to the
most general class.
• Even if the most general class cannot handle the request,
the request can be discarded.
• It is not mandatory for some class or the other to handle
the request.
Interpreter Pattern
• While designing a compiler for any programming language,
the designer comes across terminal and non-terminal
expressions.
• For e.g. If there are productions of the form
• statement ->begin statement-list end
• statement-list -> statement
• statement-list -> statement ; statement-list
• then ‘begin’, ‘end’ and ‘; ‘are terminal symbols as there
are no productions derived from them.
• ‘statement-list’ and ‘statement’ are non-terminal symbols.
• The terminals and the non=terminals have to be
interpreted separately.
• The interpreter describes the rules to define a grammar for
a particular language and interpret statements in that
language.
Class Diagram for Interpreter Pattern
Interpreter Pattern
• The program has an abstract class called
AbstractExpression that has Interpret().
• Sub-classes ‘TerminalExpression’ and
‘NonTerminalExpression’ implement the
Interpret() method in their own unique manner.
• In the main method new terminal nad nonterminal expressions are added to an ArrayList.
Then for every expression in the ArrayList, the
Interpret() method is called.
Interpreter Pattern
• This particular pattern can be used in algebraic
computations when the program has to perform
calculations based on the algebraic string that
the user enters.
• The grammar used in the implementation of the
Interpreter pattern can be revised after the
parser to parse through the expression has been
built.
• However, if the grammar becomes syntactically
complex the program becomes harder to
maintain.
Memento Pattern
• Sometimes it is necessary to store the current
state of an object and make it possible to be
retrieved later without violating the ObjectOriented principle of Encapsulation.
• E.g. There is a class called InsuranceCustomer
with the private data name, phone and email.
• The Memento class also has these variables.
InsuranceCustomer also has methods
saveMemento( ) that returns an object of the
type Memento and restoreMemento() that
restores the original values of the variables.
• The third class is the Memory class that stores a
reference to Memento and has methods to get
and set the Memento.
Memento Pattern
• Consider a scenario where we try to simulate a situation in an
Insurance office.
• A customer’s file is open wherein a second customer arrives.
• The original customer’s data has to be temporarily saved, the
second customer must be serviced and then first customer’s data
has to be retrieved again.
• So initially an object of the class InsuranceCustomer is created
and appropriate values are assigned to the variables of this class.
• These values are printed.
• Then these values are saved in a Memento object and new values
are assigned to the variables present within InsuranceCustomer
object.
• These new values are displayed.
• After that the original values are retrieved from the Memento, the
variables within InsuranceCustomer object are reassigned these
values and the values are displayed.
Memento Pattern
• In Design Patterns parlance there are 3 designations for
objects.
• The Originator is the object whose data we desire to save.
i.e.InsuranceCustomer object.
• The Memento object does the actual saving of the
data.i.e.Memento object.
• The Caretaker object manages the timing of the saving of
the state.i.e.Memory object.
Template Pattern
• A template is a class in which certain methods
may be defined but others may be left for the
derived classes to implement.
• E.g.An abstract class called TitleInfo which
contains 3 methods that have a default
implementation.
• These methods are setTitle(), getTitle() and
processTitleInfo()
• It has 1 abstract method getTitleBlurb()
• The classes BookInfo and DvDInfo implement
getTilteBlurb() in their own way.
Class Diagram for Template Pattern
Template Pattern
• Usually a template class has 4 types of methods.
• Concrete methods are present in the base class and they are
completely defined. The derived classes use these methods
directly without making any change.
• Abstract methods are those that are only declared within the
base class. Each derived class has to implement them in their
own manner.
• Hook methods are those that have a default implementation in
the base class but could be overridden in the derived classes.
• The last type of method is the method which itself calls a
combination of concrete, hook and abstract methods
(implemented in the derived class).
Command Pattern
• The Command Pattern is used to forward a user request to
a specific module.
• The request is enclosed within an object and a known
public interface is given.
• E.g. There is a screen with 2 options "File" and "Edit" in the
menu.
• If the user selects "File", he is given a list of commands i.e.
new open and exit.
• If the user selects "Edit", he is given a list of commands i.e.
Undo, Cut, Copy and Paste.
• On clicking any command under File or Edit (except exit),
the user will get a message box which will tell him the
name of the command that he has clicked on.
• On clicking exit, the program will exit.
Command Pattern
• Command pattern forwards the request to the
object of that specific class only.
• E.g.If the user request is Open, control is
transferred to that object and the printing of the
message is enclosed within its
"actionperformed" method.
• In the implementation of the Command Pattern
an object must not know the capabilities of
other objects or their manner of working.
Command Pattern
• In our example, each object New, Open, Exit,
Undo, Cut, Copy, Paste perform specific tasks.
• Each of these objects has no knowledge about
the capabilities of the other objects.
• Upon the receipt of a request from the GUI that
specific object performs its task.
• No chain exists and an object does not forward
any request to other objects.
• The only disadvantage of using the Command
pattern is the presence of a large number of
classes (and therefore objects) in the program.
Iterator Pattern
• It provides facilities to move through a collection of data
using a standard interface.
• It is not necessary to know how data is stored internally.
• E.g.Using Java’s Vector class and the Iterator interface.
• A user-defined class called VectorIterator implements
Java’s Iterator interface.
• This interface has the following methods hasNext(), next()
and remove().
• The hasNext()method returns true if there are any more
elements else it returns false.
• The next() method returns the next element.
• The remove() method removes the current element.
Iterator Pattern
• VectorIterator has a reference to Java’s Vector
class.
• Eight integer objects are added to the Vector.
• The iterator is then used to print the contents of
the Vector.
• Then the first element is removed and the
iterator is again used to print the contents.
• Iterators can be used to perform special
processing operations.
• Other iterators like Java’s ListIterator that
allows you to access data in both directions and
modify any element can be used.
Class Diagram for Iterator Pattern
Iterator Pattern
• Questions to be addressed while using the
iterator pattern.
• Suppose the program and/or the data is
very large and the iterator moves through
the elements only occasionally.
• Then it is quite possible for the original
data to get changes in the collection as
the iterator moves through it.
• It is also possible for some other thread to
change the data in the collection.
Iterator Pattern
• The second question pertains to the
compatibility between the data structure
used to store the data and the iterator.
• In our example we have used Java’s inbuilt iterator interface which the data
structure (Vector) used to store the data
is compatible. I
• In the case of our own data structure and
own iterators, provisions must be made to
let the iterator access the elements stored
in our own data structure.
Iterator Pattern
• The next question pertains to the use of
internal iterators.
• Internal iterators are those that move
through a collection of data and perform
operations without any specific request
from the user.
• E.g.Upon receipt of data to plot a graph,
all floating-point numbers could be
normalized between 0 and 100.
• Internal iterators are less common.
Benefits of using Design Patterns
• Design Patterns contribute towards reuse of
code (which is a very crucial objective of
analyzing, designing and coding solutions to
problems in an object-oriented manner.)
• Developers who have had years of experience in
software development field document the
patterns that they have identified over time.
• These problems and the tried and tested
solutions to them can be used to build powerful
systems.
Dangers
of using Design Patterns
• However the very use of these "tried and tested
solutions" in a frequent manner by the
developer hinders his creativity.
• A developer might not bother to explore
alternate solutions that can provide a more
efficient answer to the encountered problem.
• Excessive use of patterns can lead to overdesigning a system when a simpler design
would have been more appropriate.
• A developer may use Design Patterns without
ascertaining the feasibility of using them. This
can make the software difficult to develop and
maintain.