Oliver Haase
Design Patterns
Command
Description
2
‣ Purpose: Encapsulate a command as an object. Allows to dynamically configure an invoker with a command object.
Invoker can invoke command without knowing its specifics, nor the receiver of the command.
‣ Also Known As: Action, Transaction
Motivation & Remarks
‣ Most widely known application of the command pattern:
event listeners for GUI programming
‣ Remark: Command pattern is the object-oriented
counterpart of function pointers in procedural languages
‣ Remark II: If the command object contains only one
operation, function pointers can be considered more
lightweight and thus more appropriate
Remarks
‣ Remark III: In C#, a function pointer is called a delegate.
Example:
4 // C#
public delegate boolean FUNC(object x, object y);
public boolean Compare (object x, object y) { ... } public boolean contains (object x , object[ ] field) { CMP_Func myFuncObj = new FUNC(Compare) ;
foreach ( object obj in field ) f if ( myFuncObj ( obj , x ) ) return true;
}
return false;
}
Motivation
‣ In Java Swing, when a JButton is pressed, the button
invokes the actionPerformed method of a pre-registered
ActionListener command object.
‣ The ActionListener interface contains only the
actionPerformed method.
‣ an ActionListener command object can be registered
using the JButton 's addActionListener method.
Another Remark
‣ Remark IV: In Java, an anonymous class might be a good
choice to avoid the fully-fledged declaration of a class for a single method that is called only once:
6
JButton submitButton = new JButton ( "submit" ) ;
submitButton.addActionListener (new ActionListener( ) { public void actionPerformed( ActionEvent e) {
// do whatever is needed to submit }
} ) ;
Sample Structure
MyApplication
actionPerformed() ActionListener
action() MyModel
model.action() actionPerformed()
model
MyActionListener actionListener
JButton
Applicability
Use the command pattern if you want to
‣ dynamically configure an object with an action;
‣ support →undo functionality;
‣ keep a log of the executed actions so they can be redone in case of a crash;
‣ model a complex transaction;
→ in this case the encapsulation of the transaction in a command object reduces code dependencies.
8
General Structure
Client
execute() Command
action() Receiver
receiver.action() execute()
receiver
ConcreteCommand command
Invoker
• defines action to be performed
• defines receiver
declares interface for command invocation invokes the command
through the Command interface.
creates a concrete command object and passes the receiver
into it.
knows how to perform
the action.
Interactions
‣ Client creates concrete command object and determines the receiver
‣ Invoker stores the concrete command object
‣ Invoker executes a request by invoking the command object's execute operation
‣ If a command can be undone, the command object stores the receiver's original state so it can be restored later
‣ The concrete command object implements the request by calling some operation at the receiver object
10
Undo & Redo
‣ provide an additional undo operation in the Command
interface
‣ Invoker stores the concrete command object
‣ in each ConcreteCommand class, store the state before execution of the execute operation; this may include:
• all parameters for the action performed by the receiver
• all state information of the receiver that might change due to the execution of the action ( → memento pattern)
‣ receiver must allow command object to restore receiver's original state
How to implement chains of undos and redos:
Undo & Redo
‣ Client stores all executed commands in a command history
→ depth of command history determines number of possible undo/redo steps
‣ command objects are copied before insertion into command history
12
How to implement chains of undos and redos:
Consequences
‣ Command pattern decouples the entity that invokes a request ( Invoker ) from the one that knows how to implement it ( Command )
‣ Command objects can be manipulated (configured) and extended as any other object.
‣ Command objects can be composed to build macro
objects. For this purpose, the composite pattern can be employed.
‣ New command objects can easily be created without modifying existing classes.
‣ Command objects can be replaced at runtime
→ useful, e.g., for context-sensitive menus
Related Patterns
‣ The Composite pattern can be used to build macro
commands (in which case the MacroCommand class doesn't point to a receiver object)
‣ If a command needs to store the receiver's state (undo), it can use the →Memento pattern
‣ If a command object needs to be copied before being
inserted into the command history, then it behaves like a Prototype
14
Iterator
Purpose
16
Give sequential access to the individual elements of a complex object structure without revealing its internals.
Also known as: Cursor
Sample Structure
Client
iterator() List
iterator() ArrayList
hasNext() next()
Iterator
hasNext() next()
ArrayListIterator
iterator() Vector
hasNext() next()
VectorIterator
Consequences / Benefits
Using an iterator, a structure can be traversed
‣ multiple times at the same time;
‣ in different orders without changing the structure’s interface.
18
General Structure
Client
createIterator() Aggregate
return new
ConcreteIterator() createIterator()
ConcreteAggregate
hasNext() next()
Iterator
hasNext() next()
ConcreteIterator
• implements Iterator interface defines operation to
create iterator instance
creates concrete iterator
defines interface to access and traverse elements of an
aggregate uses concrete aggregate through Aggregate and
concrete iterator through Iterator interface.
Privileged Access
‣ friend class concept (C++): make iterator friend of aggregate
‣ non-static member classes (Java): Beware, publication of an inner class instance implicitly also publishes outer instance.
20
Iterators usually have privileged access to the elements of an
aggregate. This can be achieved through
Robust Iterators
‣ It can be dangerous to modify an aggregate while it is being traversed
‣ robust iterators don't get affected
→ possible techniques:
• iterator works on deep copy of aggregate
→ potentially out-dated snapshot
• iterator is registered with aggregate, aggregate notifies
iterators about modifications
Java Iterator Interface
‣ the Java collection framework uses the Iterator pattern
‣ each implementation of Collection<E> implements the interface Iterable<E>:
22 interface Iterable<E> {
Iterator<E> iterator();
}
interface Iterator<E> { boolean hasNext();
E next();
void remove();
}
‣ custom aggregate classes can and should also implement
Iterable and provide appropriate iterators.
Java Iterator Interface
‣ sample usage:
for ( Iterator<ElementType> it = aggregate.iterator(); it.hasNext(); ) { iterator.next().use();
}
‣ or, as a for-each loop:
for ( ElementType element : aggregate ) { element.use();
}
‣ the for-each loop is internally translated into the above
for loop.
Java Iterator Interface
24
What’s wrong with the following code snipplet?
public static void useVector(Vector<T> vector) { for (T element : vector)
element.use();
}
Not threadsafe, because vector might get modified while being iterated! - This is true even though Vector is a
synchronized collection.
Concurrent modification of underlying collection may result in ConcurrentModificationException
→ iterator fail-fast, but on a best effort basis, i.e. applications
must not rely on it
Java Iterator Interface
Possible Solutions:
1. copy vector, iterate on the copy → performance cost, iterates over a potentially outdated snapshot
2. client-side locking:
public static void useVector(Vector<T> vector) { synchronized ( vector ) {
for (T element: vector) element.use();
} }
→ prevents other threads from modifying vector
during iteration, but also from accessing vector at all!
Java Iterator Interface
What’s wrong with the following code snipplet?
26
public static void filterVector(Vector<T> vector) { for (T element : vector)
if ( !element.isValid() ) vector.remove(element);
}
Same thread modifies vector while being iterated
→ ConcurrentModificationException!
Java Iterator Interface
Solution: modify vector through iterator, not directly.
public static void filterVector(Vector<T> vector) {
for (Iterator<T> it = vector.iterator(); it.hasNext(); ) if ( ! it.next().isValid() )
it.remove();
}
Hidden Iterators
28
What’s wrong with the following class?
public class HiddenIterator {
private final Set<Integer> set = new HashSet<Integer>();
public synchronized void add(Integer i) { set.add(i); }
public synchronized void remove(Integer i) { set.remove(); }
public void addTenThings() { Random r = new Random();
for ( int i = 0; i < 10; i++ ) add(r.nextInt());
System.out.println(“Added ten elements to “ + set);
} }
set.toString() contains a hidden iterator
→ not threadsafe!
Hidden Iterators
The following methods that operate on collections all contain hidden iterators:
‣ toString()
‣ hashCode()
‣ equals()
‣ containsAll()
‣ removeAll()
‣ retainAll()
‣ constructors that take collections as arguments
called if collection is used as key or
element of another collection
Iterating Concurrent Collections
S ince Java 5.0, Collection framework contains several
concurrent collections that allow for concurrent access while still being threadsafe, including:
‣ ConcurrentHashMap ( → lock striping)
‣ CopyOnWriteArrayList (→ new copy for each modification)
‣ ConcurrentLinkedQueue ( → lock striping)
30
Iterators on concurrent collections are weakly consistent
→ traverse elements as they were at time of iterator construction
→ cannot throw ConcurrentModificationException !
Related Patterns
‣ Iterators are often used for recursive structures such as Composita
‣ For iterator creation, aggregate defines a factory method
‣ Iterators can use the →Memento pattern to store the state
of an iteration.
Visitor
32
Purpose
Separate algorithm from the object structure upon which it
operates.
Motivation
Consider the following list structure:
34 Client
sum(): int
chars(): String List
sum(): int
chars(): String NIL
tail
Element
sum(): int chars: String head: int
IntElement
sum(): int chars: String head: char
CharElement
[compare: J. Bloch, Effective Java, 2nd Edition, item 43: Return
empty arrays or collections, not null]
Motivation
public interface List { int sum();
String chars();
}
@Immutable // even stateless
public class Nil implements List {
@Override public String chars() { return ""; } @Override public int sum() { return 0; }
}
public abstract class Element implements List { protected final List tail;
protected Element(List tail) { this.tail = tail; } }
Motivation
36
@Immutable
public class IntElement extends Element { private final int head;
public IntElement(int number, List tail) { super(tail);
head = number;
}
@Override public String chars() { return tail.chars(); } @Override public int sum() { return head + tail.sum(); } }
@Immutable
public class CharElement extends Element { private char head;
public CharElement(char character, List tail) { super(tail);
head = character;
}
@Override public String chars() { return head + tail.chars(); } @Override public int sum() { return tail.sum(); }
}
Motivation
public class Client {
public static void main(String[] args) { List l =
new IntElement(4,
new CharElement('b', new CharElement('a', new IntElement(3, new Nil()))));
System.out.println("Sum: " + l.sum());
System.out.println("Characters: " + l.chars());
} }
Sample Usage:
Motivation
Problem: Introduction of a new operation, e.g.
38
requires modification of
‣ List interface
‣ IntElement class
‣ CharElement class
Generally, of all classes of the object structure.
boolean contains (char c);
Key Idea
⇓
‣ Add an accept(Visitor) method to each element type.
‣ In each specific visitor, provide one visit(ElementType)
operation per ElementType .
‣ To visit an element, visitor calls element’s accept operation which in turn calls the visitor’s appropriate
visit(ElementType) operation.
Idea: Separate operations ( sum() , chars() , …) into visitor
classes that traverse the object structure. Prepare object
structure to let operations traverse it.
Sample Structure
40 Client
accept(Visitor) List
accept(Visitor) NIL
tail
Element
accept(Visitor) head: int
IntElement
accept(Visitor) head: char
CharElement visit(NIL)
visit(IntElement) visit(CharElement)
Visitor
visit(NIL)
visit(IntElement) visit(CharElement)
SumVisitor
visit(NIL)
visit(IntElement) visit(CharElement)
CharVisitor
Sample Implementation
public interface List {
void accept(Visitor visitor);
}
@Immutable // even stateless
public class Nil implements List {
@Override public void accept(Visitor visitor) { visitor.visit(this);
} }
public abstract class Element implements List { protected List tail;
protected Element(List tail) { this.tail = tail;
}
public List getTail() { return tail; } }
Sample Implementation
42
@Immutable
public class IntElement extends Element { private int head;
public IntElement(int number, List tail) { super(tail);
head = number;
}
public int getHead() { return head; }
@Override public void accept(Visitor visitor) { visitor.visit(this);
} }
public interface Visitor { void visit(Nil list);
void visit(IntElement list);
void visit(CharElement list);
}
Sample Implementation
@NotThreadSafe // must be run thread-confined public class SumVisitor implements Visitor { private int sum = 0;
@Override public void visit(Nil list) {}
@Override public void visit(IntElement list) { sum += list.getHead();
list.getTail().accept(this);
}
@Override public void visit(CharElement list) { list.getTail().accept(this);
}
public int getSum() { return sum; } }
Please note: visitor can (and sometimes must) store state
information.
Sample Implementation
44 public class Client {
public static void main(String[] args) { List l =
new IntElement(4,
new CharElement('b', new CharElement('a', new IntElement(3, new Nil()))));
SumVisitor sv = new SumVisitor();
l.accept(sv);
System.out.println("Summe: " + sv.getSum());
CharsVisitor cv = new CharsVisitor();
l.accept(cv);
System.out.println("Summe: " + cv.getChars());
} }
Sample Usage:
General Structure
Client
accept(Visitor) Element
accept(Visitor)
ConcreteElementA
accept(Visitor)
ConcreteElementB visit(ConcreteElementA)
visit(ConcreteElementB) Visitor
visit(ConcreteElementA) visit(ConcreteElementB)
ConcreteVisitor
Please note: Concrete elements need not have a common supertype.
• provides implementation for each overloaded visit operation
• can store state information
• provides operation to retrieve final state declares an overloaded visit operation
for each concrete element type.
defines accept operation with a visitor as argument.
implements accept operation, usually by
calling visitor’s appropriate
visit operation.
Consequences of Modifications
46
modify operation modify object structure w/o visitor
pattern adapt all
structural classes adapt only affected structural class
with visitor
pattern adapt only
affected visitor adapt all visitor classes
Visitor pattern is beneficial if object structure is more stable
than operations on it.
Advanced Considerations
might seem awkward. It is only necessary, because most OO languages (including Java and C#) support only single dispatch rather than double dispatch.
v: ConcreteVisitor e:ConcreteElement
e.accept(v)
visit(this) :Client
The interaction sequence
Advanced Considerations
48
Desirable:
‣ in client, call visitor’s appropriate overloaded visit operation, depending on element type
v: ConcreteVisitor e:ConcreteElement v.visit(e)
:Client
‣ doube dispatch: selection of visit depends on both e ’s type
and v ’s runtime type
Advanced Considerations
‣ single dispatch polymorhism: method call v.visit(e) depends on v ’s runtime type, but only on e ’s static type.
v: ConcreteVisitor e:ConcreteElement
e.accept(v)
visit(this) :Client
use single dispatch polymorhism to call correct e ’s accept method
use overloading to call
correct visit method.
Advanced Considerations
50
If client inspects the runtime type of an element, it can directly call the visitor’s appropriate visit operations without the
indirection via the element's accept operation:
...
if ( l instanceof Nil ) { v.visit((Nil) list);
}
if ( l instanceof IntElement ) { v.visit((IntElement) list);
}
if ( l instanceof CharElement ) { v.visit((CharElement) list);
}
Advanced Considerations
This task can be placed into visitor:
public abstract class Visitor {
public final void visit(List list) { if ( list instanceof Nil ) {
visit((Nil) list);
}
if ( list instanceof IntElement ) { visit((IntElement) list);
}
if ( list instanceof CharElement ) { visit((CharElement) list);
} }
abstract public void visit(Nil list);
abstract public void visit(IntElement list);
abstract public void visit(CharElement list);
}
Advanced Considerations
52
@NotThreadSafe // must be run thread-confined public class SumVisitor extends Visitor {
private int sum = 0;
public void visit(Nil list) {}
public void visit(IntElement list) { sum += list.getHead();
visit(list.getTail());
}
public void visit(CharElement list) { visit(list.getTail());
}
public int getSum() { return sum; } }
Advanced Considerations
public interface List {}
public class Nil implements List {}
public abstract class Element implements List { protected List tail;
protected Element(List tail) { this.tail = tail;
}
public List getTail() { return tail; } }
Now, list structure does not need accept method any more:
Advanced Considerations
54
@Immutable
public class IntElement extends Element { private int head;
public IntElement(int number, List tail) { super(tail);
head = number;
}
public int getHead() { return head; } }
public class Client {
public static void main(String[] args) {
List l = new IntElement(4, new CharElement('b',
new CharElement('a', new IntElement(3, new Nil()))));
SumVisitor sv = new SumVisitor();
sv.visit(l);
System.out.println("Summe: " + sv.getSum());
CharsVisitor cv = new CharsVisitor();
cv.visit(l);
System.out.println("Summe: " + cv.getChars());
} }
Even More Advanced Considerations
public abstract class Visitor {
final public void visit(List list) { Object[] os = {list};
Class<?>[] cs = {list.getClass()};
try {
this.getClass().getMethod("visit", cs).invoke(this, os);
}
catch ( Exception e) { ... } }
abstract public void visit(Nil list);
abstract public void visit(IntElement list);
abstract public void visit(CharElement list);
}