• Keine Ergebnisse gefunden

Design Patterns & Refactoring Visitor Oliver Haase

N/A
N/A
Protected

Academic year: 2022

Aktie "Design Patterns & Refactoring Visitor Oliver Haase"

Copied!
25
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Design Patterns & Refactoring

Visitor

Oliver Haase

HTWG Konstanz

(2)

Description

Classification: Object-based behavioral pattern

Purpose: Separate algorithm from the object structure upon which it

operates.

(3)

Motivation

interfac e 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

(4)

Motivation

p u b l i c i n t e r f a c e L i s t { i n t sum ( ) ;

S t r i n g c h a r s ( ) ; }

p u b l i c c l a s s N i l implements L i s t { p u b l i c S t r i n g c h a r s ( ) { r e t u r n ” ” ; } p u b l i c i n t sum ( ) { r e t u r n 0 ; } }

p u b l i c a b s t r a c t c l a s s E l e m e n t implements L i s t { p r o t e c t e d L i s t t a i l ;

p r o t e c t e d E l e m e n t ( L i s t t a i l ) { t h i s. t a i l = t a i l ; } }

(5)

Motivation

p u b l i c c l a s s I n t E l e m e n t e x t e n d s E l e m e n t { p r i v a t e i n t h e a d ;

p u b l i c I n t E l e m e n t (i n t number , L i s t t a i l ) { s u p e r( t a i l ) ;

h e a d = number ; }

p u b l i c S t r i n g c h a r s ( ) { r e t u r n t a i l . c h a r s ( ) ; } p u b l i c i n t sum ( ) { r e t u r n h e a d + t a i l . sum ( ) ; } }

p u b l i c c l a s s C h a r E l e m e n t e x t e n d s E l e m e n t { p r i v a t e c h a r h e a d ;

p u b l i c C h a r E l e m e n t (c h a r c h a r a c t e r , L i s t t a i l ) { s u p e r( t a i l ) ;

h e a d = c h a r a c t e r ; }

p u b l i c S t r i n g c h a r s ( ) { r e t u r n h e a d + t a i l . c h a r s ( ) ; } p u b l i c i n t sum ( ) { r e t u r n t a i l . sum ( ) ; }

}

(6)

Motivation

p u b l i c c l a s s C l i e n t {

p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {

L i s t l = new I n t E l e m e n t ( 4 , new C h a r E l e m e n t ( ’ b ’ , new C h a r E l e m e n t ( ’ a ’ , new I n t E l e m e n t ( 3 ,

new N i l ( ) ) ) ) ) ;

Syst em . o u t . p r i n t l n ( ”Summe : ” + l . sum ( ) ) ; Syst em . o u t . p r i n t l n ( ”Summe : ” + l . c h a r s ( ) ) ; }

}

(7)

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.

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

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

(10)

Sample Structure

interfac e 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 inte rface Vis itor

+ vis it(Nil): void + vis it(IntElement): void + vis it(CharElement): void

S umVis itor + vis it(Nil): void + vis it(IntElement): void + vis it(CharElement): void

Chars Vis itor + vis it(Nil): void + vis it(IntElement): void + vis it(CharElement): void

(11)

Sample Implementation

p u b l i c i n t e r f a c e L i s t {

v o i d a c c e p t ( V i s i t o r v i s i t o r ) ; }

p u b l i c c l a s s N i l implements L i s t { p u b l i c v o i d a c c e p t ( 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) ; }

}

p u b l i c a b s t r a c t c l a s s E l e m e n t implements L i s t { p r o t e c t e d L i s t t a i l ;

p r o t e c t e d E l e m e n t ( L i s t t a i l ) { t h i s. t a i l = t a i l ;

}

p u b l i c L i s t g e t T a i l ( ) { r e t u r n t a i l ; } }

(12)

Sample Implementation

p u b l i c c l a s s I n t E l e m e n t e x t e n d s E l e m e n t { p r i v a t e i n t h e a d ;

p u b l i c I n t E l e m e n t (i n t number , L i s t t a i l ) { s u p e r( t a i l ) ;

h e a d = number ; }

p u b l i c i n t g e t H e a d ( ) { r e t u r n h e a d ; } p u b l i c v o i d a c c e p t ( 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) ; }

}

p u b l i c i n t e r f a c e V i s i t o r { v o i d v i s i t ( N i l l i s t ) ;

v o i d v i s i t ( I n t E l e m e n t l i s t ) ; v o i d v i s i t ( C h a r E l e m e n t l i s t ) ; }

(13)

Sample Implementation

p u b l i c c l a s s S u m V i s i t o r implements V i s i t o r { p r i v a t e i n t sum = 0 ;

p u b l i c v o i d v i s i t ( N i l l i s t ) {}

p u b l i c v o i d v i s i t ( I n t E l e m e n t l i s t ) { sum += l i s t . g e t H e a d ( ) ;

l i s t . g e t T a i l ( ) . a c c e p t (t h i s) ; }

p u b l i c v o i d v i s i t ( C h a r E l e m e n t l i s t ) { l i s t . g e t T a i l ( ) . a c c e p t (t h i s) ;

}

p u b l i c i n t getSum ( ) { r e t u r n sum ; } }

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

(14)

Sample Implementation

p u b l i c c l a s s C l i e n t {

p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {

L i s t l = new I n t E l e m e n t ( 4 , new C h a r E l e m e n t ( ’ b ’ , new C h a r E l e m e n t ( ’ a ’ , new I n t E l e m e n t ( 3 ,

new N i l ( ) ) ) ) ) ;

S u m V i s i t o r s v = new S u m V i s i t o r ( ) ; l . a c c e p t ( s v ) ;

Syst em . o u t . p r i n t l n ( ”Summe : ” + s v . getSum ( ) ) ; C h a r s V i s i t o r c v = new C h a r s V i s i t o r ( ) ;

l . a c c e p t ( c v ) ;

Syst em . o u t . p r i n t l n ( ”Summe : ” + c v . g e t C h a r s ( ) ) ; }

}

(15)

General Structure

interfac e Element + accept(Visitor): void Client

Conc reteElementA + accept(Visitor): void

inte rface Vis itor

+ vis it(ConcreteElementA): void + vis it(ConcreteElementB): void

Conc reteElementB + accept(Visitor): void

Concre te Vis itor

+ vis it(ConcreteElementA): void + vis it(ConcreteElementB): void

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

(16)

Participants

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

ConreteVisitor :

provide implementation for each overloadedvisitoperation 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.

(17)

Consequences of Modifications

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.

(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

(19)

Advanced Considerations

The interaction sequence

Conc reteVis itor Conc reteElement 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.

(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:

p u b l i c a b s t r a c t c l a s s V i s i t o r {

f i n a l p u b l i c v o i d v i s i t ( L i s t l i s t ) { i f ( l i s t i n s t a n c e o f N i l ) {

v i s i t ( ( N i l ) l i s t ) ; }

i f ( l i s t i n s t a n c e o f I n t E l e m e n t ) { v i s i t ( ( I n t E l e m e n t ) l i s t ) ;

}

i f ( l i s t i n s t a n c e o f C h a r E l e m e n t ) { v i s i t ( ( C h a r E l e m e n t ) l i s t ) ;

} }

a b s t r a c t p u b l i c v o i d v i s i t ( N i l l i s t ) ;

a b s t r a c t p u b l i c v o i d v i s i t ( I n t E l e m e n t l i s t ) ;

(21)

Advanced Considerations

p u b l i c c l a s s S u m V i s i t o r e x t e n d s V i s i t o r { p r i v a t e i n t sum = 0 ;

p u b l i c v o i d v i s i t ( N i l l i s t ) {}

p u b l i c v o i d v i s i t ( I n t E l e m e n t l i s t ) { sum += l i s t . g e t H e a d ( ) ;

v i s i t ( l i s t . g e t T a i l ( ) ) ; }

p u b l i c v o i d v i s i t ( C h a r E l e m e n t l i s t ) { v i s i t ( l i s t . g e t T a i l ( ) ) ;

}

p u b l i c i n t getSum ( ) { r e t u r n sum ; } }

(22)

Advanced Considerations

p u b l i c i n t e r f a c e L i s t {}

p u b l i c c l a s s N i l implements L i s t {}

p u b l i c a b s t r a c t c l a s s E l e m e n t implements L i s t { p r o t e c t e d L i s t t a i l ;

p r o t e c t e d E l e m e n t ( L i s t t a i l ) { t h i s. t a i l = t a i l ;

}

p u b l i c L i s t g e t T a i l ( ) { r e t u r n t a i l ; } }

(23)

Advanced Considerations

p u b l i c c l a s s I n t E l e m e n t e x t e n d s E l e m e n t { p r i v a t e i n t h e a d ;

p u b l i c I n t E l e m e n t (i n t number , L i s t t a i l ) { s u p e r( t a i l ) ;

h e a d = number ; }

p u b l i c i n t g e t H e a d ( ) { r e t u r n h e a d ; } }

(24)

Advanced Considerations

p u b l i c c l a s s C l i e n t {

p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {

L i s t l = new I n t E l e m e n t ( 4 , new C h a r E l e m e n t ( ’ b ’ ,

new C h a r E l e m e n t ( ’ a ’ , new I n t E l e m e n t ( 3 , new N i l ( ) ) ) ) ) ; S u m V i s i t o r s v = new S u m V i s i t o r ( ) ;

s v . v i s i t ( l ) ;

Syste m . o u t . p r i n t l n ( ”Summe : ” + s v . getSum ( ) ) ; C h a r s V i s i t o r c v = new C h a r s V i s i t o r ( ) ;

c v . v i s i t ( l ) ;

Syste m . o u t . p r i n t l n ( ”Summe : ” + c v . g e t C h a r s ( ) ) ; }

}

(25)

Even More Advanced Consideration

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

p u b l i c a b s t r a c t c l a s s V i s i t o r {

f i n a l p u b l i c v o i d v i s i t ( L i s t l i s t ) { O b j e c t [ ] o s = {l i s t};

C l a s s<?>[] c s = {l i s t . g e t C l a s s ( )}; t r y {

t h i s. g e t C l a s s ( ) . g e t M e t h o d ( ” v i s i t ” , c s ) . i n v o k e (t h i s , o s ) ; }

c a t c h ( E x c e p t i o n e ) { . . . } }

a b s t r a c t p u b l i c v o i d v i s i t ( N i l l i s t ) ;

a b s t r a c t p u b l i c v o i d v i s i t ( I n t E l e m e n t l i s t ) ; a b s t r a c t p u b l i c v o i d v i s i t ( C h a r E l e m e n t l i s t ) ; }

Referenzen

ÄHNLICHE DOKUMENTE

A change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior..

Communication is centralized in broker (mediator) object Broker is responsible to preserve consistency. Broker is single point of failure and scalability bottle-neck Communication

plain text documents, even though its functionality is applicable to other document types as well;. Difficult to use document mock-up

Implementor (CommImpl): defines interface for implementation classes (can differ from Abstraction interface). ConcreteImplementor (TcpCommunication): provides implementation

knows which subsystem classes are responsible for which requests delegates client requests to respective subsytem

Purpose: Define method for object creation in abstract class, leave actual creation to concrete subclasses.. Also known as:

Divide object state into intrinsic and extrinsic state, such that there is only a small number of distinct objects with different intrinsic states.. Share these

When an RMI server object is exported, the runtime system (Java virtual machine) creates a dynamic proxy (RMI stub) that implements the respective remote interface, and forwards