design patterns refactoring
play

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


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

  2. Description Classification : Object-based behavioral pattern Purpose : Separate algorithm from the object structure upon which it operates. Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 2 / 24

  3. Motivation interface Lis t Client + sum(): int + chars(): String Nil Element - tail: List + sum(): int + sum(): int + chars(): String + chars(): String IntElement CharElement - head: int - head: char - tail: List - tail: List + sum(): int + sum(): int + chars(): String + chars(): String Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 3 / 24

  4. Motivation L i s t { public i n t e r f a c e 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

  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 ; } S t r i n g chars () { return t a i l . chars ( ) ; } public sum () { return head + t a i l . sum ( ) ; } public i n t } CharElement Element { public c l a s s extends head ; private char CharElement ( char character , L i s t t a i l ) { public 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

  6. Motivation C l i e n t { public c l a s s main ( S t r i n g [ ] args ) { public s t a t i c void 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

  7. Motivation Problem: Introduction of a new operation, e.g. charCount() , requires Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 7 / 24

  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

  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

  10. Sample Structure Client interface Lis t + accept(Visitor): void Nil Element - tail: List + accept(Visitor): void + accept(Visitor): void interface Vis itor + visit(Nil): void IntElement CharElement + visit(IntElement): void - head: int - head: char + visit(CharElement): void - tail: List - tail: List + accept(Visitor): void + accept(Visitor): void S umVis itor Chars Vis itor + visit(Nil): void + visit(Nil): void + visit(IntElement): void + visit(IntElement): void + visit(CharElement): void + visit(CharElement): void Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 9 / 24

  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 ; } L i s t g e t T a i l () { return t a i l ; } public } Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 10 / 24

  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 ) ; } } V i s i t o r { public i n t e r f a c e 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 ) ; void } Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 11 / 24

  13. Sample Implementation SumVisitor V i s i t o r { public c l a s s implements 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

  14. Sample Implementation C l i e n t { public c l a s s main ( S t r i n g [ ] args ) { public s t a t i c void 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

  15. General Structure interface Element Client + accept(Visitor): void ConcreteElementA ConcreteElementB + accept(Visitor): void + accept(Visitor): void interface Vis itor + visit(ConcreteElementA): void + visit(ConcreteElementB): 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

  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

  17. Consequences of Modifications modify operation modify object structure w/o visitor adapt all structural adapt only affected pattern classes structural class with visitor adapt only affected adapt all visitor classes pattern visitor Visitor pattern is beneficial if object structure is more stable than operations on it. Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 16 / 24

  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

  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

  20. Advanced Considerations If the visitor inspects the runtime type of an element, it can directly call its own appropriate visit operations without the indirection via the element’s accept operation: V i s i t o r { public abstract c l a s s v i s i t ( L i s t l i s t ) { f i n a l public void ( l i s t N i l ) { i f instanceof 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

  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 ( ) ) ; } v i s i t ( CharElement l i s t ) { public void v i s i t ( l i s t . g e t T a i l ( ) ) ; } getSum () { return sum ; } public i n t } Oliver Haase (HTWG Konstanz) Design Patterns & Refactoring 20 / 24

Recommend


More recommend