the visitor pattern (behavioral) ©softmoore consultingslide 1

Post on 21-Jan-2016

219 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

The Visitor Pattern(Behavioral)

©SoftMoore Consulting Slide 1

©SoftMoore Consulting

Visitor Pattern: Basic Idea

• Provide an operation to be performed on the elements of a data structure (e.g., a list or tree) in another object.

• Visitor represents a kind of reversed encapsulation that separates an operation from its data.

Slide 2

Motivation

• Consider a compiler that parses a program and represents the parsed program as an abstract syntax tree (AST). The AST has many different kinds of nodes, such as Assignment, Variable Reference, and Arithmetic Expression nodes.

• Possible AST operations include:– checking that all variables are defined– checking for variables being assigned before they are used– type checking– code optimization– code generation– pretty printing/formatting

©SoftMoore Consulting Slide 3

Motivation(continued)

• These operations may need to treat each type of AST node differently. One approach would be to define each operation in the specific AST class.

©SoftMoore Consulting Slide 4

AST

checkConstraints()optimize()emitCode()

AssignmentStmt

checkConstraints()optimize()emitCode()

FunctionCall

checkConstraints()optimize()emitCode()

...

AddingExpr

checkConstraints()optimize()emitCode()

Motivation(continued)

• Problems with this approach:– Adding new operations requires changing/recompiling all of the

AST classes.– It can be confusing to have constraint-checking code mixed with

optimization code in the same class.

• An alternative solution is to encapsulate a desired operation in a separate object, called a visitor. The visitor object then traverses the elements of the AST. When an AST node “accepts” the visitor, it invokes a method on the visitor that includes the node type as an parameter. The visitor then executes the operation for that node – the operation that used to be in the AST node class.

©SoftMoore Consulting Slide 5

Motivation(continued)

©SoftMoore Consulting Slide 6

ASTVisitor

visitAssignmentStmt(AssignmentStmt)visitFunctionCall(FunctionCall)

ConstraintCheckVisitor

visitAssignmentStmt(AssignmentStmt)visitFunctionCall(FunctionCall)

OptimizeVisitor

visitAssignmentStmt(AssignmentStmt)visitFunctionCall(FunctionCall)

Motivation(continued)

©SoftMoore Consulting Slide 7

AST

accept(ASTVisitor)Program *

AssignmentStmt

accept(ASTVisitor v)

FunctionCall

accept(ASTVisitor v)

v.visitAssignmentStmt(this) v.visitFunctionCall(this)

Visitor Pattern

• Intent: Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Slide 8©SoftMoore Consulting

©SoftMoore Consulting

Visitor Pattern(continued)

Applicability: Use the Visitor pattern when

• an object structure contains many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes.

• many distinct and unrelated operations need to be performed on objects in an object structure. Visitor lets you keep operations together by defining them in one class.

• the classes defining an object structure rarely change, but you often want to define new operations over the structure.

Slide 9

Visitor Pattern(continued)

©SoftMoore Consulting Slide 10

Structure

Visitor

visitConcreteElementA(ConcreteElementA)visitConcreteElementB(ConcreteElementB)

ConcreteVisitor1

visitConcreteElementA(ConcreteElementA)visitConcreteElementB(ConcreteElementB)

ConcreteVisitor2

visitConcreteElementA(ConcreteElementA)visitConcreteElementB(ConcreteElementB)

Visitor Pattern(continued)

©SoftMoore Consulting Slide 11

Structure (continued)

Element

accept(Visitor)ObjectStructure *

ConcreteElementA

accept(Visitor v)operationA()

ConcreteElementB

accept(Visitor v)operationB()

v.visitConcreteElementA(this) v.visitConcreteElementB(this)

©SoftMoore Consulting

Visitor Pattern(continued)

Participants

• Visitor– declares a visit() operation for each class of

ConcreteElement in the object structure. The operation’s name and signature identifies the class that sends the visit request to the visitor.

• ConcreteVisitor– implements each operation declared by Visitor. Each operation

implements a fragment of the algorithm defined for the corresponding class of object in the structure.

• Element– defines an accept() operation that takes a visitor as a

parameter.

Slide 12

©SoftMoore Consulting

Visitor Pattern(continued)

Participants (continued)

• ConcreteElement– implements an accept() operation that takes a visitor as a

parameter.

• ObjectStructure– can enumerate/traverse its elements.– may provide a high-level interface to allow the visitor to visit its

elements.– may be either a composite or a collection such as a list or set.

Slide 13

©SoftMoore Consulting

Visitor Pattern(continued)

Collaborations

• A client that uses the Visitor pattern must create a ConcreteVisitor object and then traverse the object structure, visiting each element with the visitor.

• When an element is visited, it calls the Visitor operation that corresponds to its class, supplying itself as an argument so that the visitor can access its state if necessary.

Slide 14

©SoftMoore Consulting

Visitor Pattern(continued)

Slide 15

Collaborations (continued)

: ConcreteVisitor: ConcreteElementB: ObjectStructure

accept(Visitor)

: ConcreteElementA

visitConcreteEltA(this)

operationA()

accept(Visitor)

visitConcreteEltB(this)

operationB()

©SoftMoore Consulting

Visitor Pattern(continued)

Consequences: The Visitor pattern

• Makes adding new operations easy. Visitors make it easy to add operations that depend on the components of complex objects. You can define a new operation over an object structure simply by adding a new visitor.

• Gathers related operations and separates unrelated ones. Related behavior isn’t spread over the classes that define the object structure; it’s localized in a visitor.

• Permits visiting across class hierarchies. In contrast to the Iterator pattern, visitors can visit objects that don’t have a common parent class; i.e., all objects in the structure are not required to have the same type.

Slide 16

©SoftMoore Consulting

Visitor Pattern(continued)

Consequences: (continued)

• Makes adding a new ConcreteElement class hard. Each new ConcreteElement gives rise to a new operation on Visitor and a corresponding implementation in every ConcreteVisitor subclass. The key consideration in applying the Visitor pattern is the stability of the Element class hierarchy.– The Visitor pattern provides the most benefit when the class

hierarchy is stable but new operations need to be added or algorithms need to be changed.

– If the Element class hierarchy is changing frequently, then it’s probably easier just to define operations on the classes that make up the structure.

Slide 17

©SoftMoore Consulting

Visitor Pattern(continued)

Consequences (continued)

• Permits accumulation of state information. A visitor can accumulate state information as it visits each element in the object structure, eliminating the need for extra parameters or global variables.

• Breaks encapsulation. Visitor’s approach assumes that the ConcreteElement interface is powerful enough to let visitors do their job. Otherwise, using a visitor could force you to compromise encapsulation.

Slide 18

Visitor Pattern(continued)

Implementation

• Double dispatch. Visitor lets you add operations to classes without changing them using a techniqueknown as double-dispatch.– single dispatch: The actual method invoked depends on the

method signature and the type of the receiver object.– double dispatch: The actual method invoked depends on the

method signature and the types of two receivers.– Operation accept() is a double-dispatch operation – the

operation that gets executed depends on both the type of Visitor and the type of Element it visits.

– Some languages (e.g., CLOS) support double-dispatch directly.

©SoftMoore Consulting Slide 19

Visitor Pattern(continued)

Implementation (continued)

• Who is responsible for traversing the object structure? The responsibility for traversal can be in any of three places.– the object structure (e.g., by having each accept() operation

traverse the elements children and call accept() on each of them recursively)

– the visitor (e.g., to implement a particularly complex traversal that depends on the results of operations on the object structure)

– in a separate iterator object

©SoftMoore Consulting Slide 20

Visitor Pattern in Java

• In package java.nio.file, support for the Visitor Pattern is provided by– the generic interface FileVisitor<T>– the generic class SimpleFileVisitor<T>

(which implements FileVisitor<T>)– static method Files.walkFileTree()

• Method Files.walkFileTree() walks a file tree rooted at a given starting file. The file tree traversal is depth-first with parameter FileVisitor invoked for each file encountered.

©SoftMoore Consulting Slide 21

Related Patterns

• Visitors can be used to apply an operation over an object structure defined by the Composite pattern.

• Visitor may be applied to do the interpretation for the Interpreter pattern.

©SoftMoore Consulting Slide 22

©SoftMoore Consulting

References

• Visitor pattern (Wikipedia)https://en.wikipedia.org/wiki/Visitor_pattern

• Visitor Pattern (Object-Oriented Design)http://www.oodesign.com/visitor-pattern.html

• Visitor Design Pattern (SourceMaking)https://sourcemaking.com/design_patterns/visitor

• NIO.2 Cookbook, Part 3 by Jeff Friesen (JavaWorld)http://www.javaworld.com/article/2928805/core-java/nio-2-cookbook-part-3.html

• Visitor (dofactory)http://www.dofactory.com/net/visitor-design-pattern

Slide 23

top related