public interface Note { void acceptNoteVisitor v; } public interface NoteVisitor { void visitAmazoneNoteAmazoneNote note; void visitGoogleNoteGoogleNote note; void visitNewsNoteNewsN
Trang 1The Visitor Pattern
Trang 2The Problem
Trang 3Show me everything in a consistent manner …
… and send it to my friend via email
oh, and send it to her phone as well
and print it …
Trang 4Some analysis music please
NewsNote
headingbyLineexcerpt
RssNote
headingtext
date
Trang 5Commonality is in the eye of the beholder
NewsNote
headingbyLineexcerpt
RssNote
headingtext
date
Note
Trang 6Need do operations in Note structure
• With a little casual application of polymorphism
6
Note
printHeading() printDetails() asPrintable() asEmailContent() asSMS()
…
Does this look bad to you?
Trang 7The solution
Visitor Pattern
• "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"
GOF
Trang 8ConcreteVisistor1
visitConcreteElement1(e : ConcreteElement1) visitConcreteElement2(e : ConcreteElement2)
ConcreteVisistor2
visitConcreteElement1(e : ConcreteElement1) visitConcreteElement2(e : ConcreteElement2)
Client
accept(v : Visitor)
visitor.visitConcreteElement1(this);
Trang 9A solution to a problem in a context
AmazoneNote GoogleNote NewsNote RssNote
Note
accept(v : NodeVisitor)
NoteVisitor
+ visitAmazoneNote() + visitGoogleNote() + visitNewsNote() + visitRssNote()
<<Interface>>
NoteHeadingPrinter NoteDetailsPrinter
Trang 10Let’s show it in code!
public interface Note {
void accept(NoteVisitor v);
}
public interface NoteVisitor {
void visitAmazoneNote(AmazoneNote note);
void visitGoogleNote(GoogleNote note);
void visitNewsNote(NewsNote note);
void visitRssNote(RssNote note);
}
Trang 11public AmazoneNote(String title, String author,
String isbn, double price) {
this.title = title;
this.author = author;
this.isbn = isbn;
this.price = price;
}
public void accept(NoteVisitor visitor) {
visitor.visitAmazoneNote(this);
}
Trang 12this.heading = heading;
this.excerpt = excerpt;
this.url = url;
Trang 13this.heading = heading;
this.byLine = byLine;
this.excerpt = excerpt;
Trang 14public RssNote(String heading, String text) {
this.heading = heading;
this.text = text;
this.date = new Date(System.currentTimeMillis());
Trang 15NoteHeadingPrinter visitor
public class NoteHeadingPrinter implements NoteVisitor {
public void visitAmazoneNote(AmazoneNote note) {
System.out.println(note.title);
}
public void visitGoogleNote(GoogleNote note) {
System.out.println(note.heading);
}
public void visitNewsNote(NewsNote note) {
System.out.println(note.heading);
}
public void visitRssNote(RssNote note) {
System.out.println(note.heading);
}
}
Trang 16public class NoteDetailsPrinter implements NoteVisitor { public void visitAmazoneNote(AmazoneNote note) {
System.out.println(note.title);
System.out.println(note.price);
}
public void visitGoogleNote(GoogleNote note) {
System.out.println(note.heading);
System.out.println(note.excerpt);
}
public void visitNewsNote(NewsNote note) {
System.out.println(note.heading);
System.out.println(note.byLine);
System.out.println(note.excerpt);
}
public void visitRssNote(RssNote note) {
System.out.println(note.heading);
System.out.println(note.text);
}
}
Trang 17NoteDetailsPrinter visitor
public class NoteDetailsPrinter implements NoteVisitor { public void visitAmazoneNote(AmazoneNote note) {
System.out.println(note.title);
System.out.println(note.price);
}
public void visitGoogleNote(GoogleNote note) {
System.out.println(note.heading);
System.out.println(note.excerpt);
}
public void visitNewsNote(NewsNote note) {
System.out.println(note.heading);
System.out.println(note.byLine);
System.out.println(note.excerpt);
}
public void visitRssNote(RssNote note) {
System.out.println(note.heading);
System.out.println(note.text);
Trang 18NoteIterator
private List<Note> sampleNotes() {
List<Note> notes = new ArrayList<Note>();
notes add( new NewsNote( "Melbourne Pushes Boundaries" , "Tim Colebatch" ,
"Melbourne is experiencing its biggest growth surge since 1960's" ));
notes add( new GoogleNote(
"Redhill Consulting Pty Ltd - Ruby on Rails plugins" , "Here are some Ruby on Rails plugins we're
notes add( new RssNote( "let's talk about tests, baby " ,
"Some long babbling about test naming heuristics" )); return notes ;
}
for (Note note : sampleNotes()) {
note accept( visitor );
System.out println();
}
}
}
Trang 19Test Drive
public class NoteTestDrive {
public static void main(String[] args) {
NoteIterator iterator = new NoteIterator();
Trang 20Output
Melbourne Pushes Boundaries
The Wolves in the Wall
Redhill Consulting Pty Ltd - Ruby on Rails Plugins
Let's talk about tests, baby
Melbourne Pushes Boundaries
Tim Colebatch
Melbourne is experiencing its biggest growth surge since the 1960's
The Wolves in the Wall
12.06
Redhill Consulting Pty Ltd - Ruby on Rails Plugins
Here are some Ruby on Rails plugins we've developed
Let's talk about tests, baby
Some long babbling about test naming heuristics
Output of
NoteHeadingPrinter
Output of NoteDetailsPrinter
Trang 21• “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, and you
want to avoid ‘polluting’ their classes with these
operations Visitor lets you keep unrelated operations
together by defining them in one class When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them”
Trang 22• “The classes defining the object structure rarely change, but you often want to define new
operations over the structure Changing the
object structure classes requires redefining the interface to all visitors, which is potentially costly
If the object structure classes change often, then it’s probably better to define the operations in
those classes”
22
Trang 23• Visitor makes adding new operations easy
• A visitor gathers related operations and
separates unrelated ones
• Adding new ConcreteElement classes is hard
• Visitors can cross object hierarchies
• Visitors can accumulate state
• Visitors may compromise encapsulation
Trang 24File Folder Examples
Folder children : ArrayList
addElement(FileSystemElement) removeElement(FileSystemElement) getElement(name)
createIterator() accept(v : Visitor)
Visitor
visitFile(file : File) visitFolder(folder : Folder)
PrintVisitor
visitFile(file : File) visitFolder(folder : Folder)
CountFileVisitor visitFile(file : File) visitFolder(folder : Folder)
Trang 25Shape Example
Dot Circle
radius : int
Square size : int
Rectangle heigth : int width : int
Area IsContain
point : CartesianPoint BoundingBox
Shape location : CartesianPoint accept()
Client
ShapeVisitor
forDot() forCircle() forSquare() forRectanle()
<<Interface>>