0% found this document useful (0 votes)
32 views

Design Patterns: David Talby

The document discusses the Observer, Mediator, Iterator, and Visitor design patterns. Observer allows defining one-to-many dependencies between objects so that changing one object automatically updates others. Mediator encapsulates complex interactions to preserve loose coupling. Iterator provides a way to access elements of an aggregate object sequentially without exposing its underlying representation. Visitor separates algorithms from the elements on which they operate.

Uploaded by

ruchikamails4901
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views

Design Patterns: David Talby

The document discusses the Observer, Mediator, Iterator, and Visitor design patterns. Observer allows defining one-to-many dependencies between objects so that changing one object automatically updates others. Mediator encapsulates complex interactions to preserve loose coupling. Iterator provides a way to access elements of an aggregate object sequentially without exposing its underlying representation. Visitor separates algorithms from the elements on which they operate.

Uploaded by

ruchikamails4901
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 44

Design Patterns

David Talby
This Lecture

More for a Document Editor
 Synchronizing Multiple Windows
 Observer
 Simplifying complex interactions
 Mediator
 Working on complex structures
 Iterator
 Visitor
12. Observer

Define a one-to-many dependency
between objects, so that changing
one automatically updates others

For example, a spreadsheet and
several charts of it are open

Changing data in a window should
be immediately reflected in all
The Requirements

Document and Chart classes must
not know each other, for reuse

Easily add new kinds of charts or
other links

A dynamic number of charts
The Solution

Terminology
 Subject and Observer
 Publisher and Subscriber
 Listeners

Subjects attach and detach
listeners, and notify of events

Clients update themselves after
receiving a notification
The Solution II

Here’s an abstract observer:
class Observer {
void update() = 0;
}

Concrete observers such as
class Chart will inherit Observer
The Solution III

Here’s the (concrete!) subject:
class Subject {
void attach(Observer *o)
{ observers.add(o); }
void detach(Observer *o)
{ observers.remove(o); }
void notify() {
for i in observers do
o->update();
}
protected:
List observers;
}
The Solution IV

Both subject and observer will
usually inherit from other classes
as well

If multiple inheritance is not
available, the observer must be a
separate class that has a reference
to the chart object and updates it

Java has a special mechanism –
Inner classes – to make this easier
The UML
The Fine Print

Observing more than one subject
 Update must include an extra
argument to tell who is updating

Observing only certain events
 Attach must include an extra
argument to tell which events
interest this observer

Observing small changes
 Update includes arguments to tell
what changed, for efficiency
The Fine Print II

Who calls Notify?
 Greedy – the subjects, on change
 Lazy – the observers, on query

Common errors
 Forgetting to detach an object when
it is destroyed
 Calling Notify in an inconsistent state

Java includes Observer as part of
the standard libraries
 In package java.util
Known Uses

All frameworks of all kinds
 MFC, COM, Java, EJB, MVC, …

Handle user interface events

Handle asynchronous messages
13. Mediator

Encapsulate a complex interaction
to preserve loose coupling

Prevent many inter-connections
between classes, which means
that changing their behavior
requires subclassing all of them

For example, a dialog box includes
many interactions of its widgets.
How do we reuse the widgets?
The Requirements

A widget is a kind of colleague

Colleague don’t know about the
interactions they participate in
 Can be reused for different dialogs

Colleagues don’t know about others
 Allow only O(n) connections

Easy to change interactions
The Solution

All colleagues talk with a mediator

The mediator knows all colleagues

Whenever a colleague changes, it
notifies its mediator

The mediator codes the interaction
logic, and calls operations on other
colleagues
The Solution II

An example interaction:
The Solution III

Only O(n) connections:
The UML
The Fine Print

The interaction logic (mediator) and
colleagues can be reused separately
and subclassed separately

Protocols are simpler since n-to-1
relations replace n-to-m relations

Abstract mediator class is unnecessary
if there’s only one mediator

Observer or mediator?
 One-to-many or many-to-many?
 Should the logic be centralized?
Known Uses

Widgets in a user interface
 Delphi and VB “hide” this pattern

Connectivity constraints in diagrams
14. Iterator

without exposing its representation

An extremely common pattern

For example, a list should support
forward and backward traversals
 Certainly not by exposing its
internal data structure

Adding traversal methods to List’s
interface is a bad idea
The Requirements

Traversal operations should be
separate from List<G>’s interface

Allow several ongoing traversals
on the same container

Reuse: it should be possible to
write algorithms such as findItem
that work on any kind of list
The Solution

Define an abstract iterator class:

class Iterator<G> {
void first() = 0;
void next() = 0;
bool isDone() = 0;
G* item() = 0;
}
The Solution II

Each data structure implementation
will also implement an iterator class:
 ListIterator<G>
 HashTableIterator<G>
 FileIterator<G>
 StringIterator<G>

Each data structure can offer more
than one iterator:
 Forward and backward iterators
 Preorder, inorder, postorder
The Solution III

For example:
class BackwardArrayIterator<G>
: public Iterator<G>
{
Array<G> *container;
int pos;
public:
BackwardArrayIterator(Array *a)
{ container = a; first(); }
next()
{ --pos; }
// other methods easy
}
The Solution IV

A data structure’s interface should return
iterators on itself:
class List<G>
{
Iterator<G>* getForwardIterator()
{ return new
ListForwardIterator(this); }
Iterator<G>* getBackwardIterator()
// similarly
}

Now every LinkedList object can have
many active iterators
The Solution V

Writing functions for containers:
void print(Iterator<int>* it)
{
for (it->first();
!it->isOver();
it->next())
cout << it->item();
}

Using them:
print(myList->getBackwardIterator());
print(myTable->getColumnItr(“Age”));
print(myTree->getPostOrderIterator());
The Requirements II

Some iterators are generic:
 Traverse every n’th item
 Traverse items that pass a filter
 Traverse only first n items
 Traverse a computed view of items

Such iterators should be coded once

It should be easy to combine such
iterators and add new ones

Their use should be transparent
The Solution

Use the Decorator design pattern

For example, FilteredIterator<G>
receives another iterator and the
filtering function in its constructor

It delegates all calls to its internal
iterator except first() and next():
void next() {
do it->next()
while (!filter(it->item() &&
!it->isOver());
}
The Solution II

It is then easy to combine such
generic iterators

Print square roots of the first 100
positive elements in a list:
print(new LimitedIterator(100,
new ComputedIterator(sqrt,
new FilteredIterator(positive,
list->getForwardIterator()))));

Adding an abstract DecoratorIterator
reduces code size if many exist
The UML
The Fine Print

Everything is a container
 Character strings
 Files, both text and records
 Socket streams over the net
 The result of a database query
 The bits of an integer
 Stream of random or prime numbers

This allows reusing the print, find and
other algorithms for all of these
The Fine Print II

Iterators may have privileged access
 They can encapsulate security rights

Kinds of abstract iterators
 Direct access iterators
 Access the previous item

Robustness issues
 Is the iterator valid after insertions or
removals from the container?

Iterators and the Composite pattern
Known Uses

All major standard libraries of
popular programming languages
 STL for C++
 The new Java containers

New libraries for file, network and
database access in C++ conform
to STL’s iterators as well
15. Visitor

Separate complex algorithms on a
complex data structure from the
structure’s representation

For example, a document is a
composite structure involved in many
complex operations
 Spell check, grammar check,
hyphenation, auto-format, …

How do we avoid cluttering Glyph
subclasses with all this code?
The Requirements

Encapsulate complex algorithms
and their data in one place

Outside the data structure

Easily support different behavior
for every kind of Glyph

Easily add new tools
The Solution

Say hello to class Visitor:
class Visitor {
public:
void visitImage(Image *i) { }
void visitRow(Row *r) { }
void visitTable(Table *t) { }
// so on for every Glyph type
}

Every tool is a subclass:
class SpellChecker : public Visitor
The Solution II

Add to Glyph’s interface the ability to
accept visitors:
void accept(Visitor *v) = 0;

Every glyph subclass accepts a visitor
by an appropriate callback:
class Image : public Glyph {
void accept(Visitor *v)
{ v->visitImage(this); }

This way the visitor is activated for the
right kind of glyph, with its data
The Solution III

Initiating a spell check (one option):
 Create a SpellChecker object
 root->accept(sc);

Graphic non-text glyphs will just ignore
the visit
 This is why Visitor includes default
empty method implementations

Composite glyphs also do nothing
 They can forward the visit to all their
children. This can be coded once in
CompositeGlyph
The Solution IV

Easy to add operations
 Word count on characters
 Filters such as sharpen on images
 Page layout changes on pages

Works on any glyph
 In particular, a dynamic selection as
long as it’s a composite glyph

Adding a tool does not require
recompilation of Glyph hierarchy
The UML
The Fine Print

The big problem: adding new Glyph
subclasses is hard
 Requires small addition of Visitor, and
recompilation of all its subclasses

How do we traverse the structure?
 Using an iterator
 From inside the accept() code
 From inside the visitxxx() code

Visitors are really just a workaround
due to the lack of double dispatch
Known Uses

Document Editors
 Spell Check, Auto-Format, …

Photo Editors
 Filters & Effects

Compilers
 Code production, pretty printing,
tests, metrics and optimizations
on the syntax tree
Summary

Pattern of patterns
 Encapsulate the varying aspect
 Interfaces
 Inheritance describes variants
 Composition allows a dynamic choice
between variants

Design patterns are old, well known
and thoroughly tested ideas
 Over twenty years!

You might also like