Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating...

55
Oliver Haase Design Patterns Command 1

Transcript of Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating...

Page 1: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Oliver Haase

Design PatternsCommand

1

Page 2: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

Page 3: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

3

Page 4: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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;}

Page 5: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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.

5

Page 6: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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 }} ) ;

Page 7: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Sample Structure

7

MyApplication

actionPerformed()

ActionListener

action()

MyModel

model.action()

actionPerformed()

model

MyActionListener

actionListener

JButton

Page 8: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

ApplicabilityUse 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

Page 9: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

General Structure

9

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.

Page 10: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

Page 11: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

11

How to implement chains of undos and redos:

Page 12: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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:

Page 13: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

13

Page 14: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

Page 15: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Iterator

15

Page 16: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Purpose

16

Give sequential access to the individual elements of a complex object structure without revealing its internals.

Also known as: Cursor

Page 17: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Sample Structure

17

Client

iterator()

List

iterator()

ArrayList

hasNext()

next()

Iterator

hasNext()

next()

ArrayListIterator

iterator()

Vector

hasNext()

next()

VectorIterator

Page 18: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

Page 19: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

General Structure

19

Client

createIterator()

Aggregate

return new ConcreteIterator()

createIterator()ConcreteAggregate

hasNext()

next()

Iterator

hasNext()next()

ConcreteIterator

•implements Iterator interface•stores current position of traversal

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.

Page 20: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

Page 21: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Robust Iterators‣ It can be dangerous to modify an aggregate while it is being

traversed

‣ robust iterators don't get affected→ possible techniques:

21

• iterator works on deep copy of aggregate → potentially out-dated snapshot

• iterator is registered with aggregate, aggregate notifies iterators about modifications

Page 22: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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.

Page 23: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Java Iterator Interface

23

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

Page 24: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

Page 25: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Java Iterator InterfacePossible Solutions:

1. copy vector, iterate on the copy → performance cost, iterates over a potentially outdated snapshot

2. client-side locking:

25

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!

Page 26: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Java Iterator InterfaceWhat’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!

Page 27: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Java Iterator InterfaceSolution: modify vector through iterator, not directly.

27

public static void filterVector(Vector<T> vector) { for (Iterator<T> it = vector.iterator(); it.hasNext(); ) if ( ! it.next().isValid() ) it.remove();}

Page 28: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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!

Page 29: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Hidden Iterators

29

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

Page 30: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Iterating Concurrent Collections Since 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!

Page 31: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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.

31

Page 32: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Visitor

32

Page 33: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Purpose

33

Separate algorithm from the object structure upon which it operates.

Page 34: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

MotivationConsider the following list structure:

34

Client

sum(): intchars(): String

List

sum(): intchars(): String

NIL

tailElement

sum(): int chars: String

head: intIntElement

sum(): int chars: String

head: charCharElement

[compare: J. Bloch, Effective Java, 2nd Edition, item 43: Return empty arrays or collections, not null]

Page 35: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Motivation

35

public interface List { int sum(); String chars();}

@Immutable // even statelesspublic 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; }}

Page 36: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Motivation

36

@Immutablepublic 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(); }}

@Immutablepublic 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(); }}

Page 37: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Motivation

37

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:

Page 38: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

MotivationProblem: 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);

Page 39: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Key Idea

39

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

Page 40: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Sample Structure

40

Client

accept(Visitor)List

accept(Visitor)NIL

tailElement

accept(Visitor)head: intIntElement

accept(Visitor)head: charCharElement

visit(NIL)visit(IntElement)visit(CharElement)

Visitor

visit(NIL)visit(IntElement)visit(CharElement)

SumVisitor

visit(NIL)visit(IntElement)visit(CharElement)

CharVisitor

Page 41: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Sample Implementation

41

public interface List { void accept(Visitor visitor);}

@Immutable // even statelesspublic 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; }}

Page 42: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Sample Implementation

42

@Immutablepublic 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);}

Page 43: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Sample Implementation

43

@NotThreadSafe // must be run thread-confinedpublic 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.

Page 44: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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:

Page 45: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

General Structure

45

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.

Page 46: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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.

Page 47: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Advanced Considerations

47

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

Page 48: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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

Page 49: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Advanced Considerations

49

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

Page 50: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

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);}

Page 51: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Advanced Considerations

51

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);}

Page 52: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Advanced Considerations

52

@NotThreadSafe // must be run thread-confinedpublic 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; }}

Page 53: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Advanced Considerations

53

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:

Page 54: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Advanced Considerations

54

@Immutablepublic 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()); }}

Page 55: Design Patterns - Hochschule Konstanzhaase/lehre/patterns/slides/C11_Behavioral1.pdfIterating Concurrent Collections Since Java 5.0, Collection framework contains several concurrent

Even More Advanced Considerations

55

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);}

With introspection, the Visitor base class can do without the switch: