Design Patterns & Refactoring Visitor Oliver Haase HTWG - - PowerPoint PPT Presentation

design patterns refactoring
SMART_READER_LITE
LIVE PREVIEW

Design Patterns & Refactoring Visitor Oliver Haase HTWG - - PowerPoint PPT Presentation

Design Patterns & Refactoring Visitor Oliver Haase HTWG Konstanz Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 1 / 24 Description Classification : Object-based behavioral pattern Purpose : Separate algorithm from the


slide-1
SLIDE 1

Design Patterns & Refactoring

Visitor Oliver Haase

HTWG Konstanz

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 1 / 24

slide-2
SLIDE 2

Description

Classification: Object-based behavioral pattern Purpose: Separate algorithm from the object structure upon which it

  • perates.

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 2 / 24

slide-3
SLIDE 3

Motivation

interface Lis t + sum(): int + chars(): String Client Nil + sum(): int + chars(): String IntElement

  • head: int
  • tail: List

+ sum(): int + chars(): String Element

  • tail: List

+ sum(): int + chars(): String CharElement

  • head: char
  • tail: List

+ sum(): int + chars(): String Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 3 / 24

slide-4
SLIDE 4

Motivation

public i n t e r f a c e L i s t { i n t sum ( ) ; S t r i n g chars ( ) ; } public c l a s s N i l implements L i s t { public S t r i n g chars () { return ”” ; } public i n t sum () { return 0; } } public abstract c l a s s Element implements L i s t { protected L i s t t a i l ; protected Element ( L i s t t a i l ) { t h i s . t a i l = t a i l ; } }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 4 / 24

slide-5
SLIDE 5

Motivation

public c l a s s IntElement extends Element { private i n t head ; public IntElement ( i n t number , L i s t t a i l ) { super ( t a i l ) ; head = number ; } public S t r i n g chars () { return t a i l . chars ( ) ; } public i n t sum () { return head + t a i l . sum ( ) ; } } public c l a s s CharElement extends Element { private char head ; public CharElement ( char character , L i s t t a i l ) { super ( t a i l ) ; head = c h a r a c t e r ; } public S t r i n g chars () { return head + t a i l . chars ( ) ; } public i n t sum () { return t a i l . sum ( ) ; } }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 5 / 24

slide-6
SLIDE 6

Motivation

public c l a s s C l i e n t { public s t a t i c void main ( S t r i n g [ ] args ) { L i s t l = new IntElement (4 , new CharElement ( ’ b ’ , new CharElement ( ’ a ’ , new IntElement (3 , new N i l ( ) ) ) ) ) ; System . out . p r i n t l n ( ”Summe: ” + l . sum ( ) ) ; System . out . p r i n t l n ( ”Summe: ” + l . chars ( ) ) ; } }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 6 / 24

slide-7
SLIDE 7

Motivation

Problem: Introduction of a new operation, e.g. charCount(), requires

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 7 / 24

slide-8
SLIDE 8

Motivation

Problem: Introduction of a new operation, e.g. charCount(), requires modification of List interface IntElement class CharElement class Generally, of all classes of the object structure.

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 7 / 24

slide-9
SLIDE 9

Key Idea

Idea: Separate operations (sum(), chars, . . . ) into visitor classes that traverse the object structure. ⇓ For each specific visitor, provide one visit operation per element type. To visit an element, call its accept operation which in turn calls the appropriate visit operation.

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 8 / 24

slide-10
SLIDE 10

Sample Structure

interface Lis t + accept(Visitor): void Client Nil + accept(Visitor): void IntElement

  • head: int
  • tail: List

+ accept(Visitor): void Element

  • tail: List

+ accept(Visitor): void CharElement

  • head: char
  • tail: List

+ accept(Visitor): void interface Vis itor + visit(Nil): void + visit(IntElement): void + visit(CharElement): void S umVis itor + visit(Nil): void + visit(IntElement): void + visit(CharElement): void Chars Vis itor + visit(Nil): void + visit(IntElement): void + visit(CharElement): void Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 9 / 24

slide-11
SLIDE 11

Sample Implementation

public i n t e r f a c e L i s t { void accept ( V i s i t o r v i s i t o r ) ; } public c l a s s N i l implements L i s t { public void accept ( V i s i t o r v i s i t o r ) { v i s i t o r . v i s i t ( t h i s ) ; } } public abstract c l a s s Element implements L i s t { protected L i s t t a i l ; protected Element ( L i s t t a i l ) { t h i s . t a i l = t a i l ; } public L i s t g e t T a i l () { return t a i l ; } }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 10 / 24

slide-12
SLIDE 12

Sample Implementation

public c l a s s IntElement extends Element { private i n t head ; public IntElement ( i n t number , L i s t t a i l ) { super ( t a i l ) ; head = number ; } public i n t getHead () { return head ; } public void accept ( V i s i t o r v i s i t o r ) { v i s i t o r . v i s i t ( t h i s ) ; } } public i n t e r f a c e V i s i t o r { void v i s i t ( N i l l i s t ) ; void v i s i t ( IntElement l i s t ) ; void v i s i t ( CharElement l i s t ) ; }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 11 / 24

slide-13
SLIDE 13

Sample Implementation

public c l a s s SumVisitor implements V i s i t o r { private i n t sum = 0; public void v i s i t ( N i l l i s t ) {} public void v i s i t ( IntElement l i s t ) { sum += l i s t . getHead ( ) ; l i s t . g e t T a i l ( ) . accept ( t h i s ) ; } public void v i s i t ( CharElement l i s t ) { l i s t . g e t T a i l ( ) . accept ( t h i s ) ; } public i n t getSum () { return sum ; } }

Please note: Visitor can (and sometimes must) store state information.

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 12 / 24

slide-14
SLIDE 14

Sample Implementation

public c l a s s C l i e n t { public s t a t i c void main ( S t r i n g [ ] args ) { L i s t l = new IntElement (4 , new CharElement ( ’ b ’ , new CharElement ( ’ a ’ , new IntElement (3 , new N i l ( ) ) ) ) ) ; SumVisitor sv = new SumVisitor ( ) ; l . accept ( sv ) ; System . out . p r i n t l n ( ”Summe: ” + sv . getSum ( ) ) ; C h a r s V i s i t o r cv = new C h a r s V i s i t o r ( ) ; l . accept ( cv ) ; System . out . p r i n t l n ( ”Summe: ” + cv . getChars ( ) ) ; } }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 13 / 24

slide-15
SLIDE 15

General Structure

interface Element + accept(Visitor): void Client ConcreteElementA + accept(Visitor): void interface Vis itor + visit(ConcreteElementA): void + visit(ConcreteElementB): void ConcreteElementB + accept(Visitor): void ConcreteVis itor + visit(ConcreteElementA): void + visit(ConcreteElementB): void

Please note: Concrete elements need not have a common supertype.

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 14 / 24

slide-16
SLIDE 16

Participants

Visitor: declares an overloaded visit operation for each concrete element type ConreteVisitor:

provide implementation for each overloaded visit operation stores state information provides operation to retrieve final state

Element: defines an accept operation with a Visitor as argument ConcreteElement: implements the accept operation, usually by calling the visitor’s appropriate visit operation.

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 15 / 24

slide-17
SLIDE 17

Consequences of Modifications

modify operation modify object structure w/o visitor pattern adapt all structural classes adapt

  • nly

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

  • perations on it.

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 16 / 24

slide-18
SLIDE 18

Traversal Logic

There are two main variants of the visitor pattern, depending on which entities contain the logic for the traversal of the object structure:

1 Visitors (see example)

+ know the desired traversal order − structural information is duplicated (object structure + all visitors)

2 Elements

+ natural place to keep structural information confined − don’t know the desired traversal order

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 17 / 24

slide-19
SLIDE 19

Advanced Considerations

The interaction sequence

ConcreteVis itor ConcreteElement accept(this) visit(this)

seems a little awkward. It is only necessary, because most OO languages (including Java and C#) support only single dispatch rather than double dispatch.

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 18 / 24

slide-20
SLIDE 20

Advanced Considerations

If the visitor inspects the runtime type of an element, it can directly call its

  • wn appropriate visit operations without the indirection via the

element’s accept operation:

public abstract c l a s s V i s i t o r { f i n a l public void v i s i t ( L i s t l i s t ) { i f ( l i s t instanceof N i l ) { v i s i t (( N i l ) l i s t ) ; } i f ( l i s t instanceof IntElement ) { v i s i t (( IntElement ) l i s t ) ; } i f ( l i s t instanceof CharElement ) { v i s i t (( CharElement ) l i s t ) ; } } abstract public void v i s i t ( N i l l i s t ) ; abstract public void v i s i t ( IntElement l i s t ) ; abstract public void v i s i t ( CharElement l i s t ) ; }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 19 / 24

slide-21
SLIDE 21

Advanced Considerations

public c l a s s SumVisitor extends V i s i t o r { private i n t sum = 0; public void v i s i t ( N i l l i s t ) {} public void v i s i t ( IntElement l i s t ) { sum += l i s t . getHead ( ) ; v i s i t ( l i s t . g e t T a i l ( ) ) ; } public void v i s i t ( CharElement l i s t ) { v i s i t ( l i s t . g e t T a i l ( ) ) ; } public i n t getSum () { return sum ; } }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 20 / 24

slide-22
SLIDE 22

Advanced Considerations

public i n t e r f a c e L i s t {} public c l a s s N i l implements L i s t {} public abstract c l a s s Element implements L i s t { protected L i s t t a i l ; protected Element ( L i s t t a i l ) { t h i s . t a i l = t a i l ; } public L i s t g e t T a i l () { return t a i l ; } }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 21 / 24

slide-23
SLIDE 23

Advanced Considerations

public c l a s s IntElement extends Element { private i n t head ; public IntElement ( i n t number , L i s t t a i l ) { super ( t a i l ) ; head = number ; } public i n t getHead () { return head ; } }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 22 / 24

slide-24
SLIDE 24

Advanced Considerations

public c l a s s C l i e n t { public s t a t i c void main ( S t r i n g [ ] args ) { L i s t l = new IntElement (4 , new CharElement ( ’ b ’ , new CharElement ( ’ a ’ , new IntElement (3 , new N i l ( ) ) ) ) ) ; SumVisitor sv = new SumVisitor ( ) ; sv . v i s i t ( l ) ; System . out . p r i n t l n ( ”Summe: ” + sv . getSum ( ) ) ; C h a r s V i s i t o r cv = new C h a r s V i s i t o r ( ) ; cv . v i s i t ( l ) ; System . out . p r i n t l n ( ”Summe: ” + cv . getChars ( ) ) ; } }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 23 / 24

slide-25
SLIDE 25

Even More Advanced Consideration

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

public abstract c l a s s V i s i t o r { f i n a l public void v i s i t ( L i s t l i s t ) { Object [ ]

  • s = { l i s t };

Class <?>[] cs = { l i s t . g e t C l a s s ( ) } ; try { t h i s . g e t C l a s s ( ) . getMethod ( ” v i s i t ” , cs ) . invoke ( this ,

  • s ) ;

} catch ( Exception e ) { . . . } } abstract public void v i s i t ( N i l l i s t ) ; abstract public void v i s i t ( IntElement l i s t ) ; abstract public void v i s i t ( CharElement l i s t ) ; }

Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 24 / 24